UNPKG

samagra-x-enketo-core

Version:

Extensible Enketo form engine

98 lines (88 loc) 4.14 kB
import Widget from '../../js/widget'; import events from '../../js/event'; import $ from 'jquery'; /** * Enhances radio buttons * * @augments Widget */ class Radiopicker extends Widget { /** * @type {string} */ static get selector() { return 'form'; } _init() { const $form = $( this.element ); const that = this; $form // Applies a data-checked attribute to the parent label of a checked radiobutton. .on( 'click', 'input[type="radio"]:not([readonly]):checked', function() { $( this ).parent( 'label' ).siblings().removeAttr( 'data-checked' ).end().attr( 'data-checked', 'true' ); } ) // Same for checkbox. .on( 'click', 'input[type="checkbox"]:not([readonly])', function() { that._updateDataChecked( this ); } ) // Detect programmatic changes to update data-checked attribute. .on( events.InputUpdate().type, 'input[type="radio"], input[type="checkbox"]', function() { this.closest( '.option-wrapper' ) .querySelectorAll( 'input[type="radio"],input[type="checkbox"]' ) .forEach( input => that._updateDataChecked( input ) ); } ) // Readonly buttons/checkboxes will not respond to clicks. .on( 'click', 'input[type="checkbox"][readonly],input[type="radio"][readonly]', event => { event.stopImmediatePropagation(); return false; } ) /* * In Safari a click on a readonly checkbox/radio button sets `checked` to true, **before** the click event fires. * This causes the model to update. The above clickhandler will set the checked back to false, but there is * no way to propagate that reversion back to the model. * * Disabling change handling on readonly checkboxes/radiobuttons is not an option, because of the scenario * described in Form.js in the comment above the change handler. * * The solution is to detect here whether the change event was triggered by a human, by checking if the * originalEvent property is defined. * * See more at https://github.com/enketo/enketo-core/issues/516 */ .on( events.Change().type, 'input[type="checkbox"][readonly],input[type="radio"][readonly]', function( event ) { const byProgram = typeof event.originalEvent === 'undefined'; if ( !byProgram ) { event.stopImmediatePropagation(); /* * For radiobuttons, this is ugly and relies on the data-checked attribute. * Without this, is it still possible to check a readonly radio button (although it won't propagate to the model). * I think this is the only remnant of the usage of data-checked in Enketo. However, it is * also still relied upon by Esri/Survey123. */ if ( this.checked && this.parentNode.dataset.checked !== 'true' ) { this.checked = false; } } return byProgram; } ) // Add unselect radio button functionality. .on( 'click', '[data-checked]>input[type="radio"]:not(.no-unselect)', function() { $( this ).prop( 'checked', false ).trigger( 'change' ).parent().removeAttr( 'data-checked' ); } ); // Defaults this.element .querySelectorAll( 'input[type="radio"]:checked, input[type="checkbox"]:checked' ) .forEach( input => this._updateDataChecked( input ) ); } /** * @param {Element} el - Element to update */ _updateDataChecked( el ) { if ( el.checked ) { el.parentNode.dataset.checked = true; } else { delete el.parentNode.dataset.checked; } } } export default Radiopicker;