@@ -392,3 +392,270 @@ document.addEventListener('reloadUrlChanged', function (evt) {
392392 }
393393 }
394394} ) ;
395+
396+ /* Load the owner dropdown when the user clicks the pencil in basics */
397+ jQuery ( document ) . on ( 'click' , '.ticket-info-basics .inline-edit-toggle.edit .rt-inline-icon' , function ( e ) {
398+ /* htmx will run for many portlets. Only run for ticket-info-basics to avoid multiple
399+ calls to the helper for the same dropdown. */
400+ if ( e . delegateTarget . className === "ticket-info-basics" ) {
401+ var owner_dropdown_delay = jQuery ( 'div.ticket-info-basics div.select-owner-dropdown-delay:not(.loaded)' ) ;
402+ loadOwnerDropdownDelay ( owner_dropdown_delay ) ;
403+ }
404+ } ) ;
405+
406+ jQuery ( document ) . on ( 'click' , '.inline-edit-toggle' , function ( e ) {
407+ e . preventDefault ( ) ;
408+ e . stopPropagation ( ) ;
409+ toggleInlineEdit ( jQuery ( this ) ) ;
410+ } ) ;
411+
412+ jQuery ( document ) . on ( 'click' , '.titlebox[data-inline-edit-behavior="click"] > .titlebox-content' , function ( e ) {
413+ if ( jQuery ( e . target ) . is ( 'input, select, textarea' ) ) {
414+ return ;
415+ }
416+
417+ // Bypass links, buttons and radio/checkbox controls too
418+ if ( jQuery ( e . target ) . closest ( 'a, button, div.custom-radio, div.custom-checkbox' ) . length ) {
419+ return ;
420+ }
421+
422+ e . preventDefault ( ) ;
423+ e . stopPropagation ( ) ;
424+ var container = jQuery ( this ) . closest ( '.titlebox' ) ;
425+ if ( container . hasClass ( 'editing' ) ) {
426+ return ;
427+ }
428+ toggleInlineEdit ( container . find ( '.inline-edit-toggle:visible' ) ) ;
429+ } ) ;
430+
431+
432+ // Hide the tooltip everywhere when the element is clicked
433+ jQuery ( document ) . on ( 'click' , '[data-bs-toggle="tooltip"]' , function ( e ) {
434+ jQuery ( '[data-bs-toggle="tooltip"]' ) . tooltip ( "hide" ) ;
435+ } ) ;
436+
437+ jQuery ( document ) . on ( 'click' , 'a.delete-attach' , function ( ) {
438+ var parent = jQuery ( this ) . closest ( 'div' ) ;
439+ var name = jQuery ( this ) . attr ( 'data-name' ) ;
440+ var token = jQuery ( this ) . closest ( 'form' ) . find ( 'input[name=Token]' ) . val ( ) ;
441+ jQuery . post ( RT . Config . WebHomePath + '/Helpers/Upload/Delete' , { Name : name , Token : token } , function ( data ) {
442+ if ( data . status == 'success' ) {
443+ parent . remove ( ) ;
444+ }
445+ } , 'json' ) ;
446+ return false ;
447+ } ) ;
448+
449+ /* Show selected file name in UI */
450+ jQuery ( document ) . on ( 'change' , '.custom-file input' , function ( e ) {
451+ jQuery ( this ) . next ( '.custom-file-label' ) . html ( e . target . files [ 0 ] . name ) ;
452+ } ) ;
453+
454+
455+ jQuery ( document ) . on ( 'input propertychange' , ':input[data-type=json]' , function ( ) {
456+ var form = jQuery ( this ) . closest ( 'form' ) ;
457+ try {
458+ JSON . parse ( jQuery ( this ) . val ( ) ) ;
459+ form . find ( 'input[type=submit]' ) . prop ( 'disabled' , false ) ;
460+ form . find ( '.invalid-json' ) . addClass ( 'hidden' ) ;
461+ } catch ( e ) {
462+ form . find ( 'input[type=submit]' ) . prop ( 'disabled' , true ) ;
463+ form . find ( '.invalid-json' ) . removeClass ( 'hidden' ) ;
464+ }
465+ } ) ;
466+
467+ jQuery ( document ) . on ( 'click' , 'a.permalink' , function ( ) {
468+ htmx . ajax ( 'GET' , RT . Config . WebPath + "/Helpers/Permalink" , {
469+ target : '#dynamic-modal' ,
470+ values : {
471+ Code : this . getAttribute ( 'data-code' ) ,
472+ URL : this . getAttribute ( 'data-url' )
473+ } ,
474+ } ) . then ( ( ) => {
475+ bootstrap . Modal . getOrCreateInstance ( '#dynamic-modal' ) . show ( ) ;
476+ } ) ;
477+ return false ;
478+ } ) ;
479+
480+ // My Week auto submit
481+ jQuery ( document ) . on ( 'change change.td' , 'div.time-tracking input[name=Date]' , function ( ) {
482+ htmx . trigger ( this . closest ( 'form' ) , 'submit' ) ;
483+ } ) ;
484+
485+ jQuery ( document ) . on ( 'change' , 'div.time-tracking input[name=UserString]' , function ( ) {
486+ this . closest ( 'form' ) . querySelector ( 'input[name=User]' ) . value = this . value ;
487+ htmx . trigger ( this . closest ( 'form' ) , 'submit' ) ;
488+ } ) ;
489+
490+ jQuery ( document ) . on ( 'click' , 'a.search-filter' , function ( e ) {
491+ const target = document . querySelector ( e . target . closest ( '.search-filter' ) . getAttribute ( 'hx-target' ) ) ;
492+ if ( target . children . length > 0 ) {
493+ bootstrap . Modal . getOrCreateInstance ( target . closest ( '.modal.search-results-filter' ) ) . show ( ) ;
494+ }
495+ else {
496+ htmx . trigger ( e . target . closest ( '.search-filter' ) , 'manual' ) ;
497+ }
498+ return false ;
499+ } ) ;
500+
501+ // Automatically reveal history widget so anchor links like #txn-586 can work
502+ jQuery ( document ) . on ( 'click' , 'a.jump-to-unread' , function ( ) {
503+ revealHistoryWidget ( ) ;
504+ } ) ;
505+
506+ // Clip content
507+ jQuery ( document ) . on ( 'click' , 'a.unclip' , function ( ) {
508+ jQuery ( this ) . siblings ( 'div.clip' ) . css ( 'height' , 'auto' ) ;
509+ jQuery ( this ) . hide ( ) ;
510+ jQuery ( this ) . siblings ( 'a.reclip' ) . show ( ) ;
511+ return false ;
512+ } ) ;
513+
514+ jQuery ( document ) . on ( 'click' , 'a.reclip' , function ( ) {
515+ var clip_div = jQuery ( this ) . siblings ( 'div.clip' ) ;
516+ clip_div . height ( clip_div . attr ( 'clip-height' ) ) ;
517+ jQuery ( this ) . siblings ( 'a.unclip' ) . show ( ) ;
518+ jQuery ( this ) . hide ( ) ;
519+ return false ;
520+ } ) ;
521+
522+ jQuery ( document ) . on ( 'click' , '.asset-create-linked-ticket' , function ( e ) {
523+ e . preventDefault ( ) ;
524+ var url = this . href . replace ( / \/ A s s e t \/ C r e a t e L i n k e d T i c k e t \. h t m l \? / g,
525+ '/Asset/Helpers/CreateLinkedTicket?' ) ;
526+
527+ htmx . ajax ( 'GET' , url , '#dynamic-modal' ) . then ( ( ) => {
528+ bootstrap . Modal . getOrCreateInstance ( '#dynamic-modal' ) . show ( ) ;
529+ } ) ;
530+ } ) ;
531+ jQuery ( document ) . on ( 'click' , '#bulk-update-create-linked-ticket' , function ( e ) {
532+ e . preventDefault ( ) ;
533+ var chkArray = [ ] ;
534+
535+ jQuery ( "input[name='UpdateAsset']:checked" ) . each ( function ( ) {
536+ chkArray . push ( jQuery ( this ) . val ( ) ) ;
537+ } ) ;
538+
539+ var selected = '' ;
540+ for ( var i = 0 ; i < chkArray . length ; i ++ ) {
541+ selected += 'Asset=' + chkArray [ i ] + '&' ;
542+ }
543+ /* selected = chkArray.join(','); */
544+ var url = RT . Config . WebHomePath + '/Asset/Helpers/CreateLinkedTicket?' + selected ;
545+ htmx . ajax ( 'GET' , url , '#dynamic-modal' ) . then ( ( ) => {
546+ bootstrap . Modal . getOrCreateInstance ( '#dynamic-modal' ) . show ( ) ;
547+ } ) ;
548+ } ) ;
549+
550+ // Disable chosing individual objects when a scrip is applied globally
551+ jQuery ( document ) . on ( 'change' , 'form[name=AddRemoveScrip] input[type=checkbox][name^=AddScrip-][value=0], form input[type=checkbox][name^=AddCustomField-][value=0]' , function ( ) {
552+ var self = jQuery ( this ) ;
553+ var checked = self . prop ( "checked" ) ;
554+
555+ self . closest ( "form" )
556+ . find ( "table.collection input[type=checkbox]" )
557+ . prop ( "disabled" , checked ) ;
558+ } ) ;
559+
560+ jQuery ( document ) . on ( 'change' , 'input[type=file]' , function ( ) {
561+ var input = jQuery ( this ) ;
562+ var warning = input . next ( ".invalid" ) ;
563+
564+ if ( ! input . val ( ) . match ( / " / ) ) {
565+ warning . hide ( ) ;
566+ } else {
567+ if ( warning . length ) {
568+ warning . show ( ) ;
569+ } else {
570+ input . val ( "" ) ;
571+ jQuery ( "<span class='invalid'>" )
572+ . text ( loc_key ( "quote_in_filename" ) )
573+ . insertAfter ( input ) ;
574+ }
575+ }
576+ } ) ;
577+
578+ jQuery ( document ) . on ( 'change' , '#UpdateType' , function ( e ) {
579+ jQuery ( ".messagebox-container" )
580+ . removeClass ( "action-response action-private" )
581+ . addClass ( "action-" + e . target . value ) ;
582+ } ) ;
583+
584+ jQuery ( document ) . on ( 'click' , '.toggle-txn-details' , function ( e ) {
585+ return toggleTransactionDetails . apply ( this ) ;
586+ } ) ;
587+
588+ jQuery ( document ) . on ( 'change' , '.article-basics [name="Type"]' , function ( ) {
589+ if ( jQuery ( this ) . val ( ) == 'Content' ) {
590+ jQuery ( '#article-type-links' ) . addClass ( 'hidden' ) ;
591+ jQuery ( '#article-type-content' ) . removeClass ( 'hidden' ) ;
592+ }
593+ else {
594+ jQuery ( '#article-type-content' ) . addClass ( 'hidden' ) ;
595+ jQuery ( '#article-type-links' ) . removeClass ( 'hidden' ) ;
596+ }
597+ } ) ;
598+
599+ jQuery ( document ) . on ( 'focus' , '[name^="article-link-"]' , function ( ) {
600+ // if input focus in last row add another row of inputs
601+ const link_div = jQuery ( this ) . parent ( ) . parent ( ) ;
602+ const links_div = link_div . parent ( ) ;
603+ if ( link_div . attr ( 'data-link-number' ) == links_div . attr ( 'data-link-count' ) ) {
604+ const link_count = parseInt ( links_div . attr ( 'data-link-count' ) ) + 1 ;
605+ links_div . attr ( 'data-link-count' , link_count ) ;
606+ let new_link_div = link_div . clone ( ) ;
607+ new_link_div . attr ( 'data-link-number' , link_count ) ;
608+ new_link_div . find ( '[name^="article-link-"]' ) . each ( function ( ) {
609+ var oldName = jQuery ( this ) . attr ( 'name' ) ;
610+ var newName = oldName . replace ( / - \d + $ / , '-' + link_count ) ;
611+ jQuery ( this ) . attr ( 'name' , newName ) ;
612+ } ) ;
613+ links_div . append ( new_link_div ) ;
614+ }
615+ } ) ;
616+
617+ // Automatically sync to set input values to ones in config files.
618+ jQuery ( document ) . on ( 'change' , 'form[name=EditConfig] input[name$="-file"]' , function ( e ) {
619+ var file_input = jQuery ( this ) ;
620+ var form = file_input . closest ( 'form' ) ;
621+ var file_name = file_input . attr ( 'name' ) ;
622+ var file_value = form . find ( 'input[name=' + file_name + '-Current]' ) . val ( ) ;
623+ var checked = jQuery ( this ) . is ( ':checked' ) ? 1 : 0 ;
624+ if ( ! checked ) return ;
625+
626+ var db_name = file_name . replace ( / - f i l e $ / , '' ) ;
627+ var db_input = form . find ( ':input[name=' + db_name + ']' ) ;
628+ var db_input_type = db_input . attr ( 'type' ) || db_input . prop ( 'tagName' ) . toLowerCase ( ) ;
629+ if ( db_input_type == 'radio' ) {
630+ db_input . filter ( '[value=' + ( file_value || 0 ) + ']' ) . prop ( 'checked' , true ) ;
631+ }
632+ else if ( db_input_type == 'select' ) {
633+ // Silently update value, otherwise the radio would be unchecked again because of select's change event.
634+ db_input . get ( 0 ) . tomselect . setValue ( file_value . length ? file_value : '__empty_value__' , true ) ;
635+ }
636+ else {
637+ db_input . val ( file_value ) ;
638+ }
639+ } ) ;
640+
641+ jQuery ( document ) . on ( 'change' , 'form[name=BuildQuery] select[name^=SelectCustomField]' , function ( ) {
642+ var form = jQuery ( this ) . closest ( 'form' ) ;
643+ var row = jQuery ( this ) . closest ( 'div.row' ) ;
644+ var val = jQuery ( this ) . val ( ) ;
645+
646+ var new_operator = form . find ( ':input[name="' + val + 'Op"]:first' ) . clone ( ) ;
647+ new_operator . attr ( 'id' , null ) . removeClass ( 'tomselected ts-hidden-accessible' ) ;
648+ row . children ( 'div.rt-search-operator' ) . children ( ) . remove ( ) ;
649+ row . children ( 'div.rt-search-operator' ) . append ( new_operator ) ;
650+
651+ var new_value = form . find ( ':input[name="ValueOf' + val + '"]:first' ) ;
652+ new_value = new_value . clone ( ) ;
653+
654+ new_value . attr ( 'id' , null ) . removeClass ( 'tomselected ts-hidden-accessible' ) ;
655+ row . children ( 'div.rt-search-value' ) . children ( ) . remove ( ) ;
656+ row . children ( 'div.rt-search-value' ) . append ( new_value ) ;
657+ if ( new_value . hasClass ( 'datepicker' ) ) {
658+ initDatePicker ( row . get ( 0 ) ) ;
659+ }
660+ initializeSelectElements ( row . get ( 0 ) ) ;
661+ } ) ;
0 commit comments