@@ -5,6 +5,7 @@ const STEP_SELECT_USERNAME = 1;
55const STEP_SELECT_PASSWORD = 2 ;
66const STEP_SELECT_TOTP = 3 ;
77const STEP_SELECT_STRING_FIELDS = 4 ;
8+ const STEP_SELECT_SUBMIT_BUTTON = 5 ;
89
910const CHECKBOX_OVERLAY_SIZE = 20 ;
1011
@@ -18,9 +19,10 @@ const PASSWORD_FIELD_CLASS = 'kpxcDefine-fixed-password-field';
1819const TOTP_FIELD_CLASS = 'kpxcDefine-fixed-totp-field' ;
1920const STRING_FIELD_CLASS = 'kpxcDefine-fixed-string-field' ;
2021
21- const inputQueryPatternStart = 'input' ;
22- const inputQueryPatternNotCheckbox = ':not([type=checkbox])' ;
23- const inputQueryPattern = ':not([disabled]):not([type=button]):not([type=radio]):not([type=color]):not([type=date]):not([type=datetime-local]):not([type=file]):not([type=hidden]):not([type=image]):not([type=month]):not([type=range]):not([type=reset]):not([type=submit]):not([type=time]):not([type=week]), select, textarea' ;
22+ const INPUT_BUTTON_QUERY_PATTERN = 'button, input[type=submit]' ;
23+ const INPUT_QUERY_PATTERNS_START = 'input' ;
24+ const INPUT_QUERY_PATTERN_NOT_CHECKBOX = ':not([type=checkbox])' ;
25+ const INPUT_QUERY_PATTERN = ':not([disabled]):not([type=button]):not([type=radio]):not([type=color]):not([type=date]):not([type=datetime-local]):not([type=file]):not([type=hidden]):not([type=image]):not([type=month]):not([type=range]):not([type=reset]):not([type=submit]):not([type=time]):not([type=week]), select, textarea' ;
2426
2527const kpxcCustomLoginFieldsBanner = { } ;
2628kpxcCustomLoginFieldsBanner . banner = undefined ;
@@ -29,8 +31,9 @@ kpxcCustomLoginFieldsBanner.created = false;
2931kpxcCustomLoginFieldsBanner . dataStep = STEP_NONE ;
3032kpxcCustomLoginFieldsBanner . infoText = undefined ;
3133kpxcCustomLoginFieldsBanner . wrapper = undefined ;
32- kpxcCustomLoginFieldsBanner . inputQueryPatternNormal = inputQueryPatternStart + inputQueryPatternNotCheckbox + inputQueryPattern ;
33- kpxcCustomLoginFieldsBanner . inputQueryPatternStringFields = inputQueryPatternStart + inputQueryPattern ;
34+ kpxcCustomLoginFieldsBanner . inputQueryPatternNormal =
35+ INPUT_QUERY_PATTERNS_START + INPUT_QUERY_PATTERN_NOT_CHECKBOX + INPUT_QUERY_PATTERN ;
36+ kpxcCustomLoginFieldsBanner . inputQueryPatternStringFields = INPUT_QUERY_PATTERNS_START + INPUT_QUERY_PATTERN ;
3437kpxcCustomLoginFieldsBanner . markedFields = [ ] ;
3538kpxcCustomLoginFieldsBanner . nonSelectedElementsPattern = `div.${ FIXED_FIELD_CLASS } :not(.${ USERNAME_FIELD_CLASS } ):not(.${ PASSWORD_FIELD_CLASS } ):not(.${ TOTP_FIELD_CLASS } ):not(.${ STRING_FIELD_CLASS } )` ;
3639
@@ -43,6 +46,7 @@ kpxcCustomLoginFieldsBanner.selection = {
4346 totpElement : undefined ,
4447 fields : [ ] ,
4548 fieldElements : [ ] ,
49+ submitButton : undefined ,
4650} ;
4751
4852kpxcCustomLoginFieldsBanner . buttons = {
@@ -100,6 +104,7 @@ kpxcCustomLoginFieldsBanner.create = async function() {
100104 const passwordButton = kpxcUI . createButton ( RED_BUTTON , tr ( 'password' ) , kpxcCustomLoginFieldsBanner . passwordButtonClicked ) ;
101105 const totpButton = kpxcUI . createButton ( GREEN_BUTTON , 'TOTP' , kpxcCustomLoginFieldsBanner . totpButtonClicked ) ;
102106 const stringFieldsButton = kpxcUI . createButton ( BLUE_BUTTON , tr ( 'stringFields' ) , kpxcCustomLoginFieldsBanner . stringFieldsButtonClicked ) ;
107+ const submitButton = kpxcUI . createButton ( BLUE_BUTTON , tr ( 'submitButton' ) , kpxcCustomLoginFieldsBanner . submitButtonClicked ) ;
103108 const clearDataButton = kpxcUI . createButton ( RED_BUTTON , tr ( 'defineClearData' ) , kpxcCustomLoginFieldsBanner . clearData ) ;
104109 const confirmButton = kpxcUI . createButton ( GREEN_BUTTON , tr ( 'defineConfirm' ) , kpxcCustomLoginFieldsBanner . confirm ) ;
105110 const closeButton = kpxcUI . createButton ( RED_BUTTON , tr ( 'defineClose' ) , kpxcCustomLoginFieldsBanner . closeButtonClicked ) ;
@@ -116,10 +121,11 @@ kpxcCustomLoginFieldsBanner.create = async function() {
116121 kpxcCustomLoginFieldsBanner . buttons . password = passwordButton ;
117122 kpxcCustomLoginFieldsBanner . buttons . totp = totpButton ;
118123 kpxcCustomLoginFieldsBanner . buttons . stringFields = stringFieldsButton ;
124+ kpxcCustomLoginFieldsBanner . buttons . submitButton = submitButton ;
119125
120126 bannerInfo . appendMultiple ( icon , infoText ) ;
121- bannerButtons . appendMultiple ( resetButton , separator , usernameButton ,
122- passwordButton , totpButton , stringFieldsButton , secondSeparator , clearDataButton , confirmButton , closeButton ) ;
127+ bannerButtons . appendMultiple ( resetButton , separator , usernameButton , passwordButton , totpButton ,
128+ stringFieldsButton , submitButton , secondSeparator , clearDataButton , confirmButton , closeButton ) ;
123129 banner . appendMultiple ( bannerInfo , bannerButtons ) ;
124130 kpxcUI . makeBannerDraggable ( banner ) ;
125131
@@ -189,7 +195,8 @@ kpxcCustomLoginFieldsBanner.usernameButtonClicked = function(e) {
189195
190196 // Reset username field selection if already set
191197 if ( kpxcCustomLoginFieldsBanner . selection . username ) {
192- kpxcCustomLoginFieldsBanner . removeSelection ( kpxcCustomLoginFieldsBanner . selection . username , `div.${ USERNAME_FIELD_CLASS } ` ) ;
198+ kpxcCustomLoginFieldsBanner . removeSelection ( kpxcCustomLoginFieldsBanner . selection . username ,
199+ `div.${ USERNAME_FIELD_CLASS } ` ) ;
193200 kpxcCustomLoginFieldsBanner . selection . username = undefined ;
194201 }
195202
@@ -207,7 +214,8 @@ kpxcCustomLoginFieldsBanner.passwordButtonClicked = function(e) {
207214
208215 // Reset password field selection if already set
209216 if ( kpxcCustomLoginFieldsBanner . selection . password ) {
210- kpxcCustomLoginFieldsBanner . removeSelection ( kpxcCustomLoginFieldsBanner . selection . password , `div.${ PASSWORD_FIELD_CLASS } ` ) ;
217+ kpxcCustomLoginFieldsBanner . removeSelection ( kpxcCustomLoginFieldsBanner . selection . password ,
218+ `div.${ PASSWORD_FIELD_CLASS } ` ) ;
211219 kpxcCustomLoginFieldsBanner . selection . password = undefined ;
212220 }
213221
@@ -225,7 +233,8 @@ kpxcCustomLoginFieldsBanner.totpButtonClicked = function(e) {
225233
226234 // Reset TOTP field selection if already set
227235 if ( kpxcCustomLoginFieldsBanner . selection . totp ) {
228- kpxcCustomLoginFieldsBanner . removeSelection ( kpxcCustomLoginFieldsBanner . selection . totp , `div.${ TOTP_FIELD_CLASS } ` ) ;
236+ kpxcCustomLoginFieldsBanner . removeSelection ( kpxcCustomLoginFieldsBanner . selection . totp ,
237+ `div.${ TOTP_FIELD_CLASS } ` ) ;
229238 kpxcCustomLoginFieldsBanner . selection . totp = undefined ;
230239 }
231240
@@ -256,6 +265,25 @@ kpxcCustomLoginFieldsBanner.stringFieldsButtonClicked = function(e) {
256265 sendMessageToFrames ( e , 'string_field_button_clicked' ) ;
257266} ;
258267
268+ kpxcCustomLoginFieldsBanner . submitButtonClicked = function ( e ) {
269+ if ( ! e . isTrusted || kpxcCustomLoginFieldsBanner . dataStep === STEP_SELECT_SUBMIT_BUTTON ) {
270+ kpxcCustomLoginFieldsBanner . backToStart ( ) ;
271+ return ;
272+ }
273+
274+ // Reset TOTP field selection if already set
275+ if ( kpxcCustomLoginFieldsBanner . selection . submitButton ) {
276+ kpxcCustomLoginFieldsBanner . removeSelection ( kpxcCustomLoginFieldsBanner . selection . submitButton ,
277+ `div.${ STRING_FIELD_CLASS } ` ) ;
278+ kpxcCustomLoginFieldsBanner . selection . submitButton = undefined ;
279+ }
280+
281+ kpxcCustomLoginFieldsBanner . prepareSubmitButtonSelection ( ) ;
282+ kpxcCustomLoginFieldsBanner . buttons . confirm . disabled = true ;
283+
284+ sendMessageToFrames ( e , 'submit_button_clicked' ) ;
285+ } ;
286+
259287kpxcCustomLoginFieldsBanner . closeButtonClicked = function ( e ) {
260288 if ( ! e . isTrusted ) {
261289 return ;
@@ -282,6 +310,8 @@ kpxcCustomLoginFieldsBanner.updateFieldSelections = function() {
282310 kpxcCustomLoginFieldsBanner . prepareTOTPSelection ( ) ;
283311 } else if ( kpxcCustomLoginFieldsBanner . dataStep === STEP_SELECT_STRING_FIELDS ) {
284312 kpxcCustomLoginFieldsBanner . prepareStringFieldSelection ( ) ;
313+ } else if ( kpxcCustomLoginFieldsBanner . dataStep === STEP_SELECT_SUBMIT_BUTTON ) {
314+ kpxcCustomLoginFieldsBanner . prepareSubmitButtonSelection ( ) ;
285315 }
286316} ;
287317
@@ -314,17 +344,20 @@ kpxcCustomLoginFieldsBanner.confirm = async function(e) {
314344 kpxc . settings [ DEFINED_CUSTOM_FIELDS ] [ location ] . password = undefined ;
315345 } else if ( currentSite . totp ?. [ 0 ] === path [ 0 ] ) {
316346 kpxc . settings [ DEFINED_CUSTOM_FIELDS ] [ location ] . totp = undefined ;
347+ } else if ( currentSite . submitButton ?. [ 0 ] === path [ 0 ] ) {
348+ kpxc . settings [ DEFINED_CUSTOM_FIELDS ] [ location ] . submitButton = undefined ;
317349 }
318350 } ;
319351
320352 const usernamePath = kpxcCustomLoginFieldsBanner . selection . username ;
321353 const passwordPath = kpxcCustomLoginFieldsBanner . selection . password ;
322354 const totpPath = kpxcCustomLoginFieldsBanner . selection . totp ;
323355 const stringFieldsPaths = kpxcCustomLoginFieldsBanner . selection . fields ;
356+ const submitButtonPath = kpxcCustomLoginFieldsBanner . selection . submitButton ;
324357 const location = kpxc . getDocumentLocation ( ) ;
325358 const currentSettings = kpxc . settings [ DEFINED_CUSTOM_FIELDS ] [ location ] ;
326359
327- if ( usernamePath || passwordPath || totpPath || stringFieldsPaths . length > 0 ) {
360+ if ( usernamePath || passwordPath || totpPath || stringFieldsPaths . length > 0 || submitButtonPath ) {
328361 if ( currentSettings ) {
329362 // Update the single selection to current settings
330363 if ( usernamePath ) {
@@ -345,13 +378,19 @@ kpxcCustomLoginFieldsBanner.confirm = async function(e) {
345378 if ( stringFieldsPaths . length > 0 ) {
346379 kpxc . settings [ DEFINED_CUSTOM_FIELDS ] [ location ] . fields = stringFieldsPaths ;
347380 }
381+
382+ if ( submitButtonPath ) {
383+ clearIdenticalField ( submitButtonPath , location ) ;
384+ kpxc . settings [ DEFINED_CUSTOM_FIELDS ] [ location ] . submitButton = submitButtonPath ;
385+ }
348386 } else {
349387 // Override all fields (default, because there's no currentSettings available)
350388 kpxc . settings [ DEFINED_CUSTOM_FIELDS ] [ location ] = {
351389 username : usernamePath ,
352390 password : passwordPath ,
353391 totp : totpPath ,
354- fields : stringFieldsPaths
392+ fields : stringFieldsPaths ,
393+ submitButton : submitButtonPath ,
355394 } ;
356395 }
357396
@@ -381,7 +420,8 @@ kpxcCustomLoginFieldsBanner.resetSelection = function() {
381420 username : undefined ,
382421 password : undefined ,
383422 totp : undefined ,
384- fields : [ ]
423+ fields : [ ] ,
424+ submitButton : undefined ,
385425 } ;
386426
387427 kpxcCustomLoginFieldsBanner . removeMarkedFields ( ) ;
@@ -423,15 +463,24 @@ kpxcCustomLoginFieldsBanner.prepareStringFieldSelection = function() {
423463 kpxcCustomLoginFieldsBanner . selectStringFields ( ) ;
424464} ;
425465
466+ kpxcCustomLoginFieldsBanner . prepareSubmitButtonSelection = function ( ) {
467+ kpxcCustomLoginFieldsBanner . infoText . textContent = tr ( 'defineChooseSubmitButton' ) ;
468+ kpxcCustomLoginFieldsBanner . dataStep = STEP_SELECT_SUBMIT_BUTTON ;
469+ kpxcCustomLoginFieldsBanner . buttons . submitButton . classList . remove ( GRAY_BUTTON_CLASS ) ;
470+ kpxcCustomLoginFieldsBanner . selectField ( 'submitButton' ) ;
471+ } ;
472+
426473kpxcCustomLoginFieldsBanner . isFieldSelected = function ( field ) {
427474 const currentFieldId = kpxcFields . setId ( field ) ;
475+ const selection = kpxcCustomLoginFieldsBanner . selection ;
428476
429477 if ( kpxcCustomLoginFieldsBanner . markedFields . some ( f => f === field ) ) {
430478 return (
431- ( kpxcCustomLoginFieldsBanner . selection . username && kpxcCustomLoginFieldsBanner . selection . usernameElement === field )
432- || ( kpxcCustomLoginFieldsBanner . selection . password && kpxcCustomLoginFieldsBanner . selection . passwordElement === field )
433- || ( kpxcCustomLoginFieldsBanner . selection . totp && kpxcCustomLoginFieldsBanner . selection . totpElement === field )
434- || kpxcCustomLoginFieldsBanner . selection . fields . some ( f => f [ 0 ] === currentFieldId [ 0 ] )
479+ ( selection . username && selection . usernameElement === field )
480+ || ( selection . password && selection . passwordElement === field )
481+ || ( selection . totp && selection . totpElement === field )
482+ || ( selection . submitButton && selection . submitButton === field )
483+ || selection . fields . some ( f => f [ 0 ] === currentFieldId [ 0 ] )
435484 ) ;
436485 }
437486
@@ -460,7 +509,7 @@ kpxcCustomLoginFieldsBanner.setSelectedField = function(elem) {
460509 kpxcCustomLoginFieldsBanner . buttons . close . textContent = tr ( 'optionsButtonCancel' ) ;
461510} ;
462511
463- // Expects 'username', 'password' or 'totp '
512+ // Expects 'username', 'password', 'totp' or 'submitButton '
464513kpxcCustomLoginFieldsBanner . selectField = function ( fieldType ) {
465514 kpxcCustomLoginFieldsBanner . eventFieldClick = function ( e ) {
466515 const field = kpxcCustomLoginFieldsBanner . getSelectedField ( e ) ;
@@ -516,9 +565,10 @@ kpxcCustomLoginFieldsBanner.selectStringFields = function() {
516565kpxcCustomLoginFieldsBanner . markFields = function ( ) {
517566 let firstInput ;
518567 const inputs = document . querySelectorAll (
519- kpxcCustomLoginFieldsBanner . dataStep === STEP_SELECT_STRING_FIELDS
520- ? kpxcCustomLoginFieldsBanner . inputQueryPatternStringFields
521- : kpxcCustomLoginFieldsBanner . inputQueryPatternNormal ) ;
568+ kpxcCustomLoginFieldsBanner . dataStep === STEP_SELECT_SUBMIT_BUTTON ? INPUT_BUTTON_QUERY_PATTERN :
569+ ( STEP_SELECT_STRING_FIELDS
570+ ? kpxcCustomLoginFieldsBanner . inputQueryPatternStringFields
571+ : kpxcCustomLoginFieldsBanner . inputQueryPatternNormal ) ) ;
522572 const zoom = kpxcUI . bodyStyle . zoom || 1 ;
523573
524574 for ( const i of inputs ) {
@@ -676,6 +726,9 @@ kpxcCustomLoginFieldsBanner.handleTopWindowMessage = function(args) {
676726 } else if ( message === 'string_field_selected' ) {
677727 kpxcCustomLoginFieldsBanner . selection . fields = selection ;
678728 kpxcCustomLoginFieldsBanner . setSelectedField ( ) ;
729+ } else if ( message === 'submitButton_selected' ) {
730+ kpxcCustomLoginFieldsBanner . selection . submitButton = selection ;
731+ kpxcCustomLoginFieldsBanner . setSelectedField ( ) ;
679732 } else if ( message === 'enable_clear_data_button' ) {
680733 kpxcCustomLoginFieldsBanner . buttons . clearData . style . display = 'inline-block' ;
681734 }
@@ -699,6 +752,8 @@ kpxcCustomLoginFieldsBanner.handleParentWindowMessage = function(args) {
699752 kpxcCustomLoginFieldsBanner . totpButtonClicked ( e ) ;
700753 } else if ( message === 'string_field_button_clicked' ) {
701754 kpxcCustomLoginFieldsBanner . stringFieldsButtonClicked ( e ) ;
755+ } else if ( message === 'submit_button_clicked' ) {
756+ kpxcCustomLoginFieldsBanner . submitButtonClicked ( e ) ;
702757 } else if ( message === 'reset_button_clicked' ) {
703758 kpxcCustomLoginFieldsBanner . reset ( ) ;
704759 } else if ( message === 'close_button_clicked' ) {
@@ -766,5 +821,7 @@ const dataStepToString = function() {
766821 return tr ( 'totp' ) ;
767822 } else if ( kpxcCustomLoginFieldsBanner . dataStep === STEP_SELECT_STRING_FIELDS ) {
768823 return tr ( 'defineStringField' ) ;
824+ } else if ( kpxcCustomLoginFieldsBanner . dataStep === STEP_SELECT_SUBMIT_BUTTON ) {
825+ return tr ( 'defineSubmitButton' ) ;
769826 }
770827} ;
0 commit comments