diff --git a/src/event/FieldVisibilityEventHandler.js b/src/event/FieldVisibilityEventHandler.js new file mode 100644 index 0000000..aa5b33d --- /dev/null +++ b/src/event/FieldVisibilityEventHandler.js @@ -0,0 +1,111 @@ +/** + * Field visibility event handler + * + * Copyright (C) 2017 LoVullo Associates, Inc. + * + * This file is part of the Liza Data Collection Framework + * + * Liza is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +const Class = require( 'easejs' ).Class; +const EventHandler = require( './EventHandler' ); +const UnknownEventError = require( './UnknownEventError' ); + + +/** + * Shows/hides fields according to event id + * + * @todo use something more appropriate than Ui + * @todo should not be concerned with data validators + */ +module.exports = Class( 'FieldVisibilityEventHandler' ) + .implement( EventHandler ) + .extend( +{ + /** + * Client UI + * @type {Ui} + */ + 'private _ui': null, + + /** + * Field data validator + * @type {DataValidator} + */ + 'private _data_validator': null, + + + /** + * Initialize with Client UI + * + * @param {Ui} stepui Client UI + * @param {DataValidator} data_validator field data validator + */ + __construct( stepui, data_validator ) + { + this._ui = stepui; + this._data_validator = data_validator; + }, + + + /** + * Show/hide specified fields + * + * If a given field is not known then it will be silently ignored; the + * callback `callback` will still be invoked. + * + * This relies on a poorly designed API that should change in the future. + * + * @param {string} event_id event id + * @param {function(*,Object)} callback continuation to invoke on completion + * + * @param {elementName:string, indexes:Array.} data + * + * @return {EventHandler} self + */ + 'public handle'( event_id, callback, { elementName: field_name, indexes } ) + { + // TODO: Law of Demeter! + const group = this._ui.getCurrentStep() + .getElementGroup( field_name ); + + // we probably should care, but we don't right now + if ( !group ) + { + callback(); + return; + } + + const action = ( () => + { + switch ( event_id ) + { + case 'show': + return group.showField.bind( group ); + + case 'hide': + return group.hideField.bind( group ); + + default: + throw UnknownEventError( `Unknown visibility event: ${event_id}` ); + } + } )(); + + this._data_validator.clearFailures( [ field_name ] ); + indexes.forEach( field_i => action( field_name, field_i ) ); + + callback(); + } +} ); diff --git a/test/event/FieldVisibilityEventHandlerTest.js b/test/event/FieldVisibilityEventHandlerTest.js new file mode 100644 index 0000000..005e0e7 --- /dev/null +++ b/test/event/FieldVisibilityEventHandlerTest.js @@ -0,0 +1,145 @@ +/** + * Test case for FieldVisibilityEventHandler + * + * Copyright (C) 2017 LoVullo Associates, Inc. + * + * This file is part of the Liza Data Collection Framework + * + * Liza is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +const event = require( '../../' ).event; +const expect = require( 'chai' ).expect; +const Class = require( 'easejs' ).Class; + +const { + FieldVisibilityEventHandler: Sut, + UnknownEventError +} = event; + + +describe( 'FieldVisibilityEventHandler', () => +{ + it( 'shows/hides each element index', done => + { + const name = 'field_name'; + const shown = { [name]: [] }; + const hidden = { [name]: [] }; + + const sut = Sut( + createMockStepUi( + name, + ( field, index ) => shown[ field ].push( index ), + ( field, index ) => hidden[ field ].push( index ) + ), + createStubDataProvider() + ); + + // purposefully sparse indexes + const show_indexes = [ 2, 4, ]; + const hide_indexes = [ 0, 3, ]; + + const show_data = { + elementName: name, + indexes: show_indexes, + }; + + const hide_data = { + elementName: name, + indexes: hide_indexes, + }; + + sut.handle( 'show', () => + { + // implicitly ensures proper name is passed + expect( shown[ name ] ).to.deep.equal( show_indexes ); + + sut.handle( 'hide', () => + { + expect( hidden[ name ] ).to.deep.equal( hide_indexes ); + done(); + }, hide_data ); + }, show_data ); + } ); + + + it( 'throws error given unknown event', () => + { + expect( () => + { + Sut( createMockStepUi() ).handle( 'unknown', () => {}, {} ); + } ).to.throw( UnknownEventError ); + } ); + + + it( 'ignores unknown groups', done => + { + expect( () => + { + Sut( { + getCurrentStep: () => ( { getElementGroup: () => null } ) + } ).handle( 'hide', done, {} ) + } ).to.not.throw( Error ); + } ); + + + it( 'clears failures on hidden fields', done => + { + const name = 'foo_bar'; + + const hide_data = { + elementName: name, + indexes: [ 0 ], + }; + + Sut( + createMockStepUi( name, () => {}, () => {} ), + createStubDataProvider( failures => + { + expect( failures ) + .to.deep.equal( [ name ] ) + + // we don't care about the rest of the processing at this + // point + done(); + } ) + ).handle( 'hide', () => {}, hide_data ); + } ); +} ); + + +function createMockStepUi( expected_name, showf, hidef ) +{ + return { + getCurrentStep: () => ( { + getElementGroup( field_name ) + { + expect( field_name ).to.equal( expected_name ); + + return { + showField: showf, + hideField: hidef, + }; + } + } ), + }; +} + + +function createStubDataProvider( fail_callback ) +{ + return { + clearFailures: fail_callback || () => {}, + }; +}