| @@ 1-215 (lines=215) @@ | ||
| 1 | 'use strict'; |
|
| 2 | var objectAssign = require( 'object-assign' ), |
|
| 3 | actions = require( './actions' ), |
|
| 4 | ||
| 5 | INTERVAL_TYPE_ONE_OFF = 0, |
|
| 6 | INTERVAL_TYPE_RECURRING = 1, |
|
| 7 | ||
| 8 | createDefaultChangeHandler = function ( store, contentName ) { |
|
| 9 | return function ( evt ) { |
|
| 10 | store.dispatch( actions.newChangeContentAction( contentName, evt.target.value ) ); |
|
| 11 | }; |
|
| 12 | }, |
|
| 13 | ||
| 14 | createRegexValidator = function ( store, contentName ) { |
|
| 15 | return function ( evt ) { |
|
| 16 | store.dispatch( actions.newValidateInputAction( |
|
| 17 | contentName, |
|
| 18 | evt.target.value, |
|
| 19 | evt.target.getAttribute( 'data-pattern' ) |
|
| 20 | ) ); |
|
| 21 | }; |
|
| 22 | }, |
|
| 23 | ||
| 24 | createNoEmptyStringValidator = function ( store, contentName ) { |
|
| 25 | return function ( evt ) { |
|
| 26 | store.dispatch( actions.newValidateInputAction( |
|
| 27 | contentName, |
|
| 28 | evt.target.value |
|
| 29 | ) ); |
|
| 30 | }; |
|
| 31 | }, |
|
| 32 | ||
| 33 | RadioComponent = { |
|
| 34 | element: null, |
|
| 35 | contentName: '', |
|
| 36 | onChange: null, |
|
| 37 | render: function ( formContent ) { |
|
| 38 | this.element.val( [ formContent[ this.contentName ] ] ); // Needs to be an array |
|
| 39 | } |
|
| 40 | }, |
|
| 41 | ||
| 42 | CheckboxComponent = { |
|
| 43 | element: null, |
|
| 44 | contentName: '', |
|
| 45 | onChange: null, |
|
| 46 | render: function ( formContent ) { |
|
| 47 | this.element.prop( 'checked', !!formContent[ this.contentName ] ); // !! converts to boolean |
|
| 48 | } |
|
| 49 | }, |
|
| 50 | ||
| 51 | TextComponent = { |
|
| 52 | element: null, |
|
| 53 | contentName: '', |
|
| 54 | onChange: null, |
|
| 55 | validator: null, |
|
| 56 | render: function ( formContent ) { |
|
| 57 | if ( this.element.val() !== formContent[ this.contentName ] ) { |
|
| 58 | // Avoid changing value while element is edited by the user |
|
| 59 | if ( !this.element.is( ':focus' ) ) { |
|
| 60 | this.element.val( formContent[ this.contentName ] ); |
|
| 61 | this.element.change(); |
|
| 62 | } |
|
| 63 | } |
|
| 64 | } |
|
| 65 | }, |
|
| 66 | ||
| 67 | AmountComponent = { |
|
| 68 | inputElement: null, |
|
| 69 | selectElement: null, |
|
| 70 | hiddenElement: null, |
|
| 71 | render: function ( formContent ) { |
|
| 72 | this.hiddenElement.val( formContent.amount || '' ); |
|
| 73 | if ( formContent.isCustomAmount ) { |
|
| 74 | this.selectElement.prop( 'checked', false ); |
|
| 75 | this.inputElement.val( formContent.amount ); |
|
| 76 | } else { |
|
| 77 | this.selectElement.val( [ formContent.amount ] ); |
|
| 78 | this.inputElement.val( '' ); |
|
| 79 | } |
|
| 80 | } |
|
| 81 | }, |
|
| 82 | ||
| 83 | PaymentIntervalComponent = { |
|
| 84 | decisionElement: null, |
|
| 85 | paymentIntervalElement: null, |
|
| 86 | render: function ( formContent ) { |
|
| 87 | var intervalType = formContent.paymentIntervalInMonths > 0 ? |
|
| 88 | INTERVAL_TYPE_RECURRING : |
|
| 89 | INTERVAL_TYPE_ONE_OFF; |
|
| 90 | this.paymentIntervalElement.val( [ formContent.paymentIntervalInMonths ] ); |
|
| 91 | this.decisionElement.val( [ intervalType ] ); |
|
| 92 | } |
|
| 93 | }, |
|
| 94 | ||
| 95 | BankDataComponent = { |
|
| 96 | ibanElement: null, |
|
| 97 | bicElement: null, |
|
| 98 | accountNumberElement: null, |
|
| 99 | bankCodeElement: null, |
|
| 100 | debitTypeElement: null, |
|
| 101 | bankNameFieldElement: null, |
|
| 102 | bankNameDisplayElement: null, |
|
| 103 | render: function ( formContent ) { |
|
| 104 | this.ibanElement.val( formContent.iban ); |
|
| 105 | this.bicElement.val( formContent.bic ); |
|
| 106 | this.accountNumberElement.val( formContent.accountNumber ); |
|
| 107 | this.bankCodeElement.val( formContent.bankCode ); |
|
| 108 | this.debitTypeElement.val( [ formContent.debitType ] ); // set as array for radio buttons/dropdown field |
|
| 109 | this.bankNameFieldElement.val( formContent.bankName ); |
|
| 110 | this.bankNameDisplayElement.text( formContent.bankName ); |
|
| 111 | } |
|
| 112 | }; |
|
| 113 | ||
| 114 | module.exports = { |
|
| 115 | ||
| 116 | INTERVAL_TYPE_ONE_OFF: INTERVAL_TYPE_ONE_OFF, |
|
| 117 | INTERVAL_TYPE_RECURRING: INTERVAL_TYPE_RECURRING, |
|
| 118 | ||
| 119 | createRadioComponent: function ( store, element, contentName ) { |
|
| 120 | var component = objectAssign( Object.create( RadioComponent ), { |
|
| 121 | element: element, |
|
| 122 | contentName: contentName, |
|
| 123 | onChange: createDefaultChangeHandler( store, contentName ) |
|
| 124 | } ); |
|
| 125 | element.on( 'change', component.onChange ); |
|
| 126 | return component; |
|
| 127 | }, |
|
| 128 | ||
| 129 | createSelectMenuComponent: function ( store, element, contentName ) { |
|
| 130 | var component = objectAssign( Object.create( RadioComponent ), { |
|
| 131 | element: element, |
|
| 132 | contentName: contentName, |
|
| 133 | onChange: createDefaultChangeHandler( store, contentName ) |
|
| 134 | } ); |
|
| 135 | element.on( 'selectmenuchange', component.onChange ); |
|
| 136 | return component; |
|
| 137 | }, |
|
| 138 | ||
| 139 | createCheckboxComponent: function ( store, element, contentName ) { |
|
| 140 | var component = objectAssign( Object.create( CheckboxComponent ), { |
|
| 141 | element: element, |
|
| 142 | contentName: contentName, |
|
| 143 | onChange: function () { |
|
| 144 | store.dispatch( actions.newChangeContentAction( contentName, !!element.prop( 'checked' ) ) ); |
|
| 145 | } |
|
| 146 | } ); |
|
| 147 | element.on( 'change', component.onChange ); |
|
| 148 | return component; |
|
| 149 | }, |
|
| 150 | ||
| 151 | createValidatingCheckboxComponent: function ( store, element, contentName ) { |
|
| 152 | var component = objectAssign( this.createCheckboxComponent( store, element, contentName ), { |
|
| 153 | validator: createNoEmptyStringValidator( store, contentName ) |
|
| 154 | } ); |
|
| 155 | element.on( 'change', component.validator ); |
|
| 156 | return component; |
|
| 157 | }, |
|
| 158 | ||
| 159 | createTextComponent: function ( store, element, contentName ) { |
|
| 160 | var component = objectAssign( Object.create( TextComponent ), { |
|
| 161 | element: element, |
|
| 162 | contentName: contentName, |
|
| 163 | onChange: createDefaultChangeHandler( store, contentName ) |
|
| 164 | } ); |
|
| 165 | element.on( 'change', component.onChange ); |
|
| 166 | return component; |
|
| 167 | }, |
|
| 168 | ||
| 169 | createValidatingTextComponent: function ( store, element, contentName ) { |
|
| 170 | var component = objectAssign( this.createTextComponent( store, element, contentName ), { |
|
| 171 | validator: createRegexValidator( store, contentName ) |
|
| 172 | } ); |
|
| 173 | element.on( 'change', component.validator ); |
|
| 174 | return component; |
|
| 175 | }, |
|
| 176 | ||
| 177 | createAmountComponent: function ( store, inputElement, selectElement, hiddenElement ) { |
|
| 178 | var component = objectAssign( Object.create( AmountComponent ), { |
|
| 179 | inputElement: inputElement, |
|
| 180 | selectElement: selectElement, |
|
| 181 | hiddenElement: hiddenElement |
|
| 182 | } ); |
|
| 183 | inputElement.on( 'change', function ( evt ) { |
|
| 184 | store.dispatch( actions.newInputAmountAction( evt.target.value ) ); |
|
| 185 | } ); |
|
| 186 | selectElement.on( 'change', function ( evt ) { |
|
| 187 | store.dispatch( actions.newSelectAmountAction( evt.target.value ) ); |
|
| 188 | } ); |
|
| 189 | return component; |
|
| 190 | }, |
|
| 191 | ||
| 192 | createPaymentIntervalComponent: function ( store, decisionElement, intervalElement ) { |
|
| 193 | var component = objectAssign( Object.create( PaymentIntervalComponent ), { |
|
| 194 | decisionElement: decisionElement, |
|
| 195 | paymentIntervalElement: intervalElement, |
|
| 196 | onChange: createDefaultChangeHandler( store, 'paymentIntervalInMonths' ) |
|
| 197 | } ); |
|
| 198 | decisionElement.on( 'change', component.onChange ); |
|
| 199 | intervalElement.on( 'change', component.onChange ); |
|
| 200 | return component; |
|
| 201 | }, |
|
| 202 | ||
| 203 | createBankDataComponent: function ( store, bankDataElements ) { |
|
| 204 | // TODO check if all elements are passed in |
|
| 205 | var component = objectAssign( Object.create( BankDataComponent ), bankDataElements ); |
|
| 206 | bankDataElements.ibanElement.on( 'change', createDefaultChangeHandler( store, 'iban' ) ); |
|
| 207 | bankDataElements.bicElement.on( 'change', createDefaultChangeHandler( store, 'bic' ) ); |
|
| 208 | bankDataElements.bicElement.on( 'change', createRegexValidator( store, 'bic' ) ); |
|
| 209 | bankDataElements.accountNumberElement.on( 'change', createDefaultChangeHandler( store, 'accountNumber' ) ); |
|
| 210 | bankDataElements.bankCodeElement.on( 'change', createDefaultChangeHandler( store, 'bankCode' ) ); |
|
| 211 | bankDataElements.debitTypeElement.on( 'change', createDefaultChangeHandler( store, 'debitType' ) ); |
|
| 212 | return component; |
|
| 213 | } |
|
| 214 | ||
| 215 | }; |
|
| 216 | ||
| @@ 1-249 (lines=249) @@ | ||
| 1 | 'use strict'; |
|
| 2 | ||
| 3 | var objectAssign = require( 'object-assign' ), |
|
| 4 | _ = require( 'underscore' ), |
|
| 5 | actions = require( './actions' ), |
|
| 6 | NumericInputHandler = require( './numeric_input_handler' ), |
|
| 7 | ||
| 8 | /** |
|
| 9 | * Wrapper around underscore debounce function with a delay of 300 milliseconds |
|
| 10 | * |
|
| 11 | * @param {function} f |
|
| 12 | * @param {Number} milliseconds |
|
| 13 | * @return {Function} |
|
| 14 | */ |
|
| 15 | defaultDebounce = function ( f, milliseconds ) { |
|
| 16 | return _.debounce( f, milliseconds || 300 ); |
|
| 17 | }, |
|
| 18 | ||
| 19 | createDefaultChangeHandler = function ( store, contentName ) { |
|
| 20 | return function ( evt ) { |
|
| 21 | store.dispatch( actions.newChangeContentAction( contentName, evt.target.value ) ); |
|
| 22 | }; |
|
| 23 | }, |
|
| 24 | ||
| 25 | createRegexValidator = function ( store, contentName ) { |
|
| 26 | return function ( evt ) { |
|
| 27 | store.dispatch( actions.newValidateInputAction( |
|
| 28 | contentName, |
|
| 29 | evt.target.value, |
|
| 30 | evt.target.getAttribute( 'data-pattern' ) |
|
| 31 | ) ); |
|
| 32 | }; |
|
| 33 | }, |
|
| 34 | ||
| 35 | createNoEmptyStringValidator = function ( store, contentName ) { |
|
| 36 | return function ( evt ) { |
|
| 37 | store.dispatch( actions.newValidateInputAction( |
|
| 38 | contentName, |
|
| 39 | evt.target.value |
|
| 40 | ) ); |
|
| 41 | }; |
|
| 42 | }, |
|
| 43 | ||
| 44 | RadioComponent = { |
|
| 45 | element: null, |
|
| 46 | contentName: '', |
|
| 47 | onChange: null, |
|
| 48 | render: function ( formContent ) { |
|
| 49 | this.element.val( [ formContent[ this.contentName ] ] ); // Needs to be an array |
|
| 50 | } |
|
| 51 | }, |
|
| 52 | ||
| 53 | SelectComponent = { |
|
| 54 | element: null, |
|
| 55 | contentName: '', |
|
| 56 | onChange: null, |
|
| 57 | render: function ( formContent ) { |
|
| 58 | ||
| 59 | if ( this.element.val() === formContent[ this.contentName ] || this.elementAndContentAreEmpty( formContent ) ) { |
|
| 60 | return; |
|
| 61 | } |
|
| 62 | ||
| 63 | this.element.val( [ formContent[ this.contentName ] ] ); |
|
| 64 | this.element.change(); |
|
| 65 | }, |
|
| 66 | elementAndContentAreEmpty: function( formContent ) { |
|
| 67 | // calling this.element.val( '' ) leads to this.element.val() === null in some cases, |
|
| 68 | // so we need to compare different types |
|
| 69 | return this.element.val() === null && formContent[ this.contentName ] === ''; |
|
| 70 | } |
|
| 71 | }, |
|
| 72 | ||
| 73 | CheckboxComponent = { |
|
| 74 | element: null, |
|
| 75 | contentName: '', |
|
| 76 | onChange: null, |
|
| 77 | render: function ( formContent ) { |
|
| 78 | this.element.prop( 'checked', !!formContent[ this.contentName ] ); // !! converts to boolean |
|
| 79 | } |
|
| 80 | }, |
|
| 81 | ||
| 82 | TextComponent = { |
|
| 83 | element: null, |
|
| 84 | contentName: '', |
|
| 85 | onChange: null, |
|
| 86 | validator: null, |
|
| 87 | render: function ( formContent ) { |
|
| 88 | if ( this.element.val() !== formContent[ this.contentName ] ) { |
|
| 89 | // Avoid changing value while element is edited by the user |
|
| 90 | if ( !this.element.is( ':focus' ) ) { |
|
| 91 | this.element.val( formContent[ this.contentName ] ); |
|
| 92 | this.element.change(); |
|
| 93 | } |
|
| 94 | } |
|
| 95 | } |
|
| 96 | }, |
|
| 97 | ||
| 98 | AmountComponent = { |
|
| 99 | inputElement: null, |
|
| 100 | selectElement: null, |
|
| 101 | hiddenElement: null, |
|
| 102 | numberFormatter: null, |
|
| 103 | render: function ( formContent ) { |
|
| 104 | this.hiddenElement.val( this.numberFormatter.format( formContent.amount ) ); |
|
| 105 | if ( formContent.isCustomAmount ) { |
|
| 106 | this.inputElement.parent().addClass( 'filled' ); |
|
| 107 | this.selectElement.prop( 'checked', false ); |
|
| 108 | this.inputElement.val( this.numberFormatter.format( formContent.amount ) ); |
|
| 109 | } else { |
|
| 110 | this.inputElement.parent().removeClass( 'filled' ); |
|
| 111 | this.selectElement.val( [ String( formContent.amount ) ] ); |
|
| 112 | this.inputElement.val( '' ); |
|
| 113 | } |
|
| 114 | } |
|
| 115 | }, |
|
| 116 | ||
| 117 | BankDataComponent = { |
|
| 118 | ibanElement: null, |
|
| 119 | bicElement: null, |
|
| 120 | accountNumberElement: null, |
|
| 121 | bankCodeElement: null, |
|
| 122 | bankNameFieldElement: null, |
|
| 123 | bankNameDisplayElement: null, |
|
| 124 | render: function ( formContent ) { |
|
| 125 | this.ibanElement.val( formContent.iban ); |
|
| 126 | this.bicElement.val( formContent.bic ); |
|
| 127 | this.accountNumberElement.val( formContent.accountNumber ); |
|
| 128 | this.bankCodeElement.val( formContent.bankCode ); |
|
| 129 | this.bankNameFieldElement.val( formContent.bankName ); |
|
| 130 | this.bankNameDisplayElement.text( formContent.bankName ); |
|
| 131 | } |
|
| 132 | }; |
|
| 133 | ||
| 134 | module.exports = { |
|
| 135 | ||
| 136 | createRadioComponent: function ( store, element, contentName ) { |
|
| 137 | var component = objectAssign( Object.create( RadioComponent ), { |
|
| 138 | element: element, |
|
| 139 | contentName: contentName, |
|
| 140 | onChange: createDefaultChangeHandler( store, contentName ) |
|
| 141 | } ); |
|
| 142 | element.on( 'change', component.onChange ); |
|
| 143 | return component; |
|
| 144 | }, |
|
| 145 | ||
| 146 | createSelectMenuComponent: function ( store, element, contentName ) { |
|
| 147 | var component = objectAssign( Object.create( SelectComponent ), { |
|
| 148 | element: element, |
|
| 149 | contentName: contentName, |
|
| 150 | onChange: createDefaultChangeHandler( store, contentName ) |
|
| 151 | } ); |
|
| 152 | element.on( 'selectmenuchange, change', component.onChange ); |
|
| 153 | return component; |
|
| 154 | }, |
|
| 155 | ||
| 156 | createCheckboxComponent: function ( store, element, contentName ) { |
|
| 157 | var component = objectAssign( Object.create( CheckboxComponent ), { |
|
| 158 | element: element, |
|
| 159 | contentName: contentName, |
|
| 160 | onChange: function () { |
|
| 161 | store.dispatch( actions.newChangeContentAction( contentName, !!element.prop( 'checked' ) ) ); |
|
| 162 | } |
|
| 163 | } ); |
|
| 164 | element.on( 'change', component.onChange ); |
|
| 165 | return component; |
|
| 166 | }, |
|
| 167 | ||
| 168 | createValidatingCheckboxComponent: function ( store, element, contentName ) { |
|
| 169 | var component = objectAssign( this.createCheckboxComponent( store, element, contentName ), { |
|
| 170 | validator: createNoEmptyStringValidator( store, contentName ) |
|
| 171 | } ); |
|
| 172 | element.on( 'change', component.validator ); |
|
| 173 | return component; |
|
| 174 | }, |
|
| 175 | ||
| 176 | createTextComponent: function ( store, element, contentName ) { |
|
| 177 | var component = objectAssign( Object.create( TextComponent ), { |
|
| 178 | element: element, |
|
| 179 | contentName: contentName, |
|
| 180 | onChange: createDefaultChangeHandler( store, contentName ) |
|
| 181 | } ); |
|
| 182 | element.on( 'change', component.onChange ); |
|
| 183 | return component; |
|
| 184 | }, |
|
| 185 | ||
| 186 | createValidatingTextComponent: function ( store, element, contentName ) { |
|
| 187 | var component = objectAssign( this.createTextComponent( store, element, contentName ), { |
|
| 188 | validator: createRegexValidator( store, contentName ) |
|
| 189 | } ); |
|
| 190 | element.on( 'change', component.validator ); |
|
| 191 | return component; |
|
| 192 | }, |
|
| 193 | ||
| 194 | /** |
|
| 195 | * @param store |
|
| 196 | * @param {jQuery} inputElement |
|
| 197 | * @param {jQuery} selectElement |
|
| 198 | * @param {jQuery} hiddenElement |
|
| 199 | * @param {CurrencyParser} numberParser |
|
| 200 | * @param {CurrencyFormatter} numberFormatter |
|
| 201 | * @return {AmountComponent} |
|
| 202 | */ |
|
| 203 | createAmountComponent: function ( store, inputElement, selectElement, hiddenElement, numberParser, numberFormatter ) { |
|
| 204 | var component = objectAssign( Object.create( AmountComponent ), { |
|
| 205 | inputElement: inputElement, |
|
| 206 | selectElement: selectElement, |
|
| 207 | hiddenElement: hiddenElement, |
|
| 208 | numberFormatter: numberFormatter |
|
| 209 | } ); |
|
| 210 | NumericInputHandler.createNumericInputHandler( inputElement, numberParser.getDecimalDelimiter() ); |
|
| 211 | inputElement.on( 'change', function ( evt ) { |
|
| 212 | var amount; |
|
| 213 | try { |
|
| 214 | amount = numberParser.parse( evt.target.value ); |
|
| 215 | } catch ( e ) { |
|
| 216 | amount = 0; |
|
| 217 | inputElement.val( '0' ); |
|
| 218 | } |
|
| 219 | store.dispatch( actions.newInputAmountAction( amount ) ); |
|
| 220 | } ); |
|
| 221 | selectElement.on( 'change', function ( evt ) { |
|
| 222 | store.dispatch( actions.newSelectAmountAction( evt.target.value ) ); |
|
| 223 | } ); |
|
| 224 | return component; |
|
| 225 | }, |
|
| 226 | ||
| 227 | createBankDataComponent: function ( store, bankDataElements ) { |
|
| 228 | var component = objectAssign( Object.create( BankDataComponent ), bankDataElements ); |
|
| 229 | bankDataElements.ibanElement.on( 'change', createDefaultChangeHandler( store, 'iban' ) ); |
|
| 230 | bankDataElements.bicElement.on( 'change', createDefaultChangeHandler( store, 'bic' ) ); |
|
| 231 | bankDataElements.bicElement.on( 'change', createRegexValidator( store, 'bic' ) ); |
|
| 232 | bankDataElements.accountNumberElement.on( 'change', createDefaultChangeHandler( store, 'accountNumber' ) ); |
|
| 233 | bankDataElements.bankCodeElement.on( 'change', createDefaultChangeHandler( store, 'bankCode' ) ); |
|
| 234 | return component; |
|
| 235 | }, |
|
| 236 | ||
| 237 | addEagerChangeBehavior: function( textComponent, debouncingFunction ) { |
|
| 238 | debouncingFunction = debouncingFunction || defaultDebounce; |
|
| 239 | textComponent.element.on( 'keypress', debouncingFunction( function ( evt ) { |
|
| 240 | textComponent.onChange( evt ); |
|
| 241 | if ( textComponent.validator ) { |
|
| 242 | textComponent.validator( evt ); |
|
| 243 | } |
|
| 244 | } ) ); |
|
| 245 | return textComponent; |
|
| 246 | }, |
|
| 247 | ||
| 248 | SelectComponent: SelectComponent |
|
| 249 | }; |
|
| 250 | ||