From 26a10eb0df6ecdc9fce36a12e62d28a6937f21c0 Mon Sep 17 00:00:00 2001 From: sindhu Date: Tue, 28 May 2024 08:11:00 +0700 Subject: [PATCH] step 1 : autocomplete multi select (di hold) --- assets/mcu/htmx4.html | 237 ++++++++++ assets/mcu/proses_obj_search.php | 33 ++ handlers/dev/xsampleautocomplete.handlers.go | 74 +++ handlers/routes.go | 6 + models/xsampleautocomplete.models.go | 7 + services/dev/xsampleautocomplete.services.go | 86 ++++ .../xsampleautocomplete.templ | 280 +++++++++++ .../xsampleautocomplete_templ.go | 443 ++++++++++++++++++ 8 files changed, 1166 insertions(+) create mode 100644 assets/mcu/htmx4.html create mode 100644 assets/mcu/proses_obj_search.php create mode 100644 handlers/dev/xsampleautocomplete.handlers.go create mode 100644 models/xsampleautocomplete.models.go create mode 100644 services/dev/xsampleautocomplete.services.go create mode 100644 views/dev/xsampleautocomplete/xsampleautocomplete.templ create mode 100644 views/dev/xsampleautocomplete/xsampleautocomplete_templ.go diff --git a/assets/mcu/htmx4.html b/assets/mcu/htmx4.html new file mode 100644 index 0000000..b08fc49 --- /dev/null +++ b/assets/mcu/htmx4.html @@ -0,0 +1,237 @@ + + + + + + Typeahead Example with HTMX + + + + + +
+

Typeahead Example with HTMX

+ + + +
+ +
+
+ + + + diff --git a/assets/mcu/proses_obj_search.php b/assets/mcu/proses_obj_search.php new file mode 100644 index 0000000..60a21ed --- /dev/null +++ b/assets/mcu/proses_obj_search.php @@ -0,0 +1,33 @@ + 1, "name" => "Alabama"], + ["id" => 2, "name" => "Alaska"], + // other data... + ["id" => 49, "name" => "Wisconsin"], + ["id" => 50, "name" => "Wyoming"], +]; + +$query = isset($_GET['query']) ? $_GET['query'] : ''; +$selected = isset($_GET['selectedvalue']) ? explode(',', $_GET['selectedvalue']) : []; + +if ($query) { + $results = array_filter($data, function($item) use ($query, $selected) { + // Filter out items that do not match the query and are already selected + return stripos($item["name"], $query) !== false && !in_array($item["id"], $selected); + }); +} else { + $results = []; +} + +// Prepare HTML response +$html = ''; +foreach ($results as $result) { + $html .= '' . htmlspecialchars($result["name"]) . ''; +} + +// Return HTML response +echo $html; +?> diff --git a/handlers/dev/xsampleautocomplete.handlers.go b/handlers/dev/xsampleautocomplete.handlers.go new file mode 100644 index 0000000..776e687 --- /dev/null +++ b/handlers/dev/xsampleautocomplete.handlers.go @@ -0,0 +1,74 @@ +package dev_handlers + +import ( + "cpone/models" + "cpone/utils" + dev_xsampleautocomplete "cpone/views/dev/xsampleautocomplete" + "fmt" + + "github.com/labstack/echo/v4" + "go.uber.org/zap" +) + +type XSampleAutoCompleteServices interface { + GetListT_Test(search string, selectedIdxArr string) ([]models.XsampleT_Test, []models.XsampleT_Test, error) +} + +func NewXSampleAutoCompleteHandler(us XSampleAutoCompleteServices) *XSampleAutoCompleteHandler { + return &XSampleAutoCompleteHandler{ + XSampleAutoCompleteServices: us, + } +} + +type XSampleAutoCompleteHandler struct { + XSampleAutoCompleteServices XSampleAutoCompleteServices +} + +// INITIAL +func (lh *XSampleAutoCompleteHandler) HandleShowXSampleAutoComplete(c echo.Context) error { + // logger, _ := zap.NewProduction() + // dataList, dataSelected, err := lh.XSampleAutoCompleteServices.GetListT_Test("", "") + + // if err != nil { + // defer logger.Sync() + // logger.Info("ERROR GET GROUP RESULT", + // zap.Any("error", err), + // ) + // fmt.Println(dataList) + // fmt.Println(dataSelected) + // return err + // } + + view := dev_xsampleautocomplete.ShowXSampleScreen("AutoComplete", + dev_xsampleautocomplete.MainAutoComplete(), + dev_xsampleautocomplete.CssXsampleAutoComplete(), + dev_xsampleautocomplete.TemplJsAutoComplete(), + dev_xsampleautocomplete.EmptyDiv1(), + dev_xsampleautocomplete.EmptyDiv1(), + dev_xsampleautocomplete.EmptyDiv1()) + return utils.View(c, view) +} + +// PROSES SEARCH +func (lh *XSampleAutoCompleteHandler) HandleSearchAutoComplete(c echo.Context) error { + logger, _ := zap.NewProduction() + + query := c.QueryParam("query") + selectedValue := c.QueryParam("selectedvalue") + + dataList, dataSelected, err := lh.XSampleAutoCompleteServices.GetListT_Test(query, selectedValue) + + if err != nil { + defer logger.Sync() + logger.Info("ERROR GET GROUP RESULT", + zap.Any("error", err), + ) + fmt.Println(dataList) + fmt.Println(dataSelected) + return err + } + + view := dev_xsampleautocomplete.ListData(dataList) + + return utils.View(c, view) +} diff --git a/handlers/routes.go b/handlers/routes.go index d1b13b1..1637884 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -291,4 +291,10 @@ func SetupRoutesDev(app *echo.Echo, appStore db.AppStore) { dev.GET("/md/groupresultv2/opendelete", devMdGRhandlers.HandleOpenDeleteForm) dev.POST("/md/groupresultv2/closedeleteform", devMdGRhandlers.HandleCloseFormDelete) dev.POST("/md/groupresultv2/delete", devMdGRhandlers.HandleDeleteUserGroup) + + // autocomplete + devAutoServices := dev_services.NewServicesXSampleAutoComplete(appStore) + devAutohandlers := dev_handlers.NewXSampleAutoCompleteHandler(devAutoServices) + dev.GET("/autocompletev1", devAutohandlers.HandleShowXSampleAutoComplete) + dev.GET("/searchautocompletev1", devAutohandlers.HandleSearchAutoComplete) } diff --git a/models/xsampleautocomplete.models.go b/models/xsampleautocomplete.models.go new file mode 100644 index 0000000..616bd45 --- /dev/null +++ b/models/xsampleautocomplete.models.go @@ -0,0 +1,7 @@ +package models + +type XsampleT_Test struct { + T_TestID int `db:"T_TestID"` + T_TestCode string `db:"T_TestCode"` + T_TestName string `db:"T_TestName"` +} diff --git a/services/dev/xsampleautocomplete.services.go b/services/dev/xsampleautocomplete.services.go new file mode 100644 index 0000000..443cf62 --- /dev/null +++ b/services/dev/xsampleautocomplete.services.go @@ -0,0 +1,86 @@ +package dev_services + +import ( + "cpone/db" + "cpone/models" + dbx "cpone/package/database" + "fmt" + "strings" + + "go.uber.org/zap" +) + +func NewServicesXSampleAutoComplete(uStore db.AppStore) *ServicesXSampleAutoComplete { + + return &ServicesXSampleAutoComplete{ + XSampleAutoCompleteStore: uStore, + } +} + +type ServicesXSampleAutoComplete struct { + XSampleAutoCompleteStore db.AppStore +} + +// LIST T_Test plus search +func (su *ServicesXSampleAutoComplete) GetListT_Test(search string, selectedIdxArr string) ([]models.XsampleT_Test, []models.XsampleT_Test, error) { + var dataList []models.XsampleT_Test + var dataListSelected []models.XsampleT_Test + // var dataListNew []models.XsampleT_Test + + logger, _ := zap.NewProduction() + defer logger.Sync() + + prm := "%" + strings.TrimSpace(search) + "%" + + // Check if selectedIdxArr is not empty + if len(selectedIdxArr) > 0 { + qrySelected := fmt.Sprintf(` + SELECT T_TestID, T_TestCode, T_TestName + FROM t_test + WHERE T_TestIsActive = 'Y' + AND T_TestID IN (%s) + LIMIT 0, 50 + `, selectedIdxArr) + + err := dbx.Handlex.Select(&dataListSelected, qrySelected) + if err != nil { + return nil, nil, fmt.Errorf("error querying database: %v", err) + } + + qryListX := fmt.Sprintf(`SELECT T_TestID, T_TestCode, T_TestName + FROM t_test + WHERE T_TestIsActive = 'Y' + AND (T_TestCode LIKE ? OR T_TestName LIKE ?) + AND T_TestID NOT IN (%s) + LIMIT 0, 50 + `, selectedIdxArr) + + logger.Info("QUERY SEARCH INITIAL TOTAL COUNT", + zap.String("query search", qryListX), + ) + + errx := dbx.Handlex.Select(&dataList, qryListX, prm, prm) + if errx != nil { + return nil, nil, fmt.Errorf("error querying database: %v", err) + } + } else { + qryList := ` + SELECT T_TestID, T_TestCode, T_TestName + FROM t_test + WHERE T_TestIsActive = 'Y' + AND (T_TestCode LIKE ? OR T_TestName LIKE ?) + LIMIT 0, 50 + ` + + logger.Info("QUERY SEARCH INITIAL TOTAL COUNT", + zap.String("query search", qryList), + ) + + err := dbx.Handlex.Select(&dataList, qryList, prm, prm) + if err != nil { + return nil, nil, fmt.Errorf("error querying database: %v", err) + } + } + + return dataList, dataListSelected, nil +} diff --git a/views/dev/xsampleautocomplete/xsampleautocomplete.templ b/views/dev/xsampleautocomplete/xsampleautocomplete.templ new file mode 100644 index 0000000..9e901d7 --- /dev/null +++ b/views/dev/xsampleautocomplete/xsampleautocomplete.templ @@ -0,0 +1,280 @@ +package dev_xsampleautocomplete + +import ( + "cpone/layout" + "cpone/models" + "strconv" +) + +templ EmptyDiv1() { +
+} + +templ Selected(data []models.XsampleT_Test) { + if len(data) > 0 { + for _, v := range data { + + { v.T_TestCode } - { v.T_TestName } + × + + } + } +} + +templ ListData(dataList []models.XsampleT_Test) { + if len(dataList) > 0 { + + } else { + + } +} + +templ MainAutoComplete() { +
+

Typeahead Example with HTMX

+ + +
+
+ @JsCustomAutoComplete() +} + +templ TemplJsAutoComplete() { +} + +script JsCustomAutoComplete() { + let selectedItems = []; + + function selectItem(element) { + var container = document.querySelector('.badge-container'); + + // Get the selected item text and id + var itemText = element.textContent; + var itemId = element.getAttribute('data-id'); + + // Check if the item is already selected + if (selectedItems.some(item => item.id === itemId)) { + return; + } + + // Add the item to the selected items list + selectedItems.push({ id: itemId, name: itemText }); + + // Create a badge element + var badge = document.createElement('span'); + badge.className = 'badge badge-primary'; + badge.textContent = itemText; + + // Create a close button + var closeBtn = document.createElement('span'); + closeBtn.className = 'badge badge-light ml-1'; + closeBtn.style.cursor = 'pointer'; + closeBtn.textContent = '×'; + closeBtn.onclick = function() { + container.removeChild(badge); + selectedItems = selectedItems.filter(item => item.id !== itemId); + updateQueryParameter(); + }; + + // Append close button to badge + badge.appendChild(closeBtn); + + // Append the badge to the container + container.appendChild(badge); + + // Clear the input + document.getElementById('search-inputx').value = ''; + + // Hide dropdown + document.getElementById('dropdown-menu').classList.remove('show'); + + // Highlight the selected item in the dropdown + element.classList.add('selected'); + + // Update query parameter + updateQueryParameter(); + } + + function updateQueryParameter() { + var selectedValues = selectedItems.map(item => item.id).join(','); + document.querySelector('input[name="selectedvalue"]').value = selectedValues; + } + + // Display loading indicator when request is in progress + document.body.addEventListener('htmx:configRequest', function(event) { + document.getElementById('loading-indicator').style.display = 'block'; + }); + + document.body.addEventListener('htmx:afterOnLoad', function(event) { + document.getElementById('loading-indicator').style.display = 'none'; + var dropdown = document.getElementById('dropdown-menu'); + if (dropdown.children.length > 0) { + dropdown.classList.add('show'); + dropdown.focus(); + var activeItem = dropdown.querySelector('.active'); + if (activeItem) { + dropdown.scrollTop = activeItem.offsetTop - dropdown.offsetTop; + } + } else { + dropdown.classList.remove('show'); + } + }); + + // Hide the dropdown when clicking outside + document.addEventListener('click', function(event) { + var isClickInside = event.target.classList.contains('search-input') || event.target.classList.contains('badge-container') || event.target.closest('.badge-container'); + if (!isClickInside) { + document.getElementById('dropdown-menu').classList.remove('show'); + } + }); + + // Handle keyboard navigation + document.getElementById('search-inputx').addEventListener('keydown', function(event) { + var dropdownMenu = document.getElementById('dropdown-menu'); + var items = dropdownMenu.querySelectorAll('.dropdown-item'); + var activeItem = dropdownMenu.querySelector('.active'); + + if (event.key === 'ArrowDown') { + event.preventDefault(); // Prevent page scroll + if (!activeItem) { + items[0].classList.add('active'); + } else { + activeItem.classList.remove('active'); + var next = activeItem.nextElementSibling; + if (next) { + next.classList.add('active'); + } else { + items[0].classList.add('active'); + } + } + } + + if (event.key === 'ArrowUp') { + event.preventDefault(); // Prevent page scroll + if (!activeItem) { + items[items.length - 1].classList.add('active'); + } else { + activeItem.classList.remove('active'); + var prev = activeItem.previousElementSibling; + if (prev) { + prev.classList.add('active'); + } else { + items[items.length - 1].classList.add('active'); + } + } + } + + if (event.key === 'Enter' && activeItem) { + selectItem(activeItem); + } + + if (activeItem) { + dropdownMenu.scrollTop = activeItem.offsetTop - dropdownMenu.offsetTop; + } + }); + + // Set the input value and hide the dropdown when an item is clicked + document.body.addEventListener('click', function(event) { + if (event.target.classList.contains('dropdown-item')) { + selectItem(event.target); + } + }); + + // Show dropdown when input gets focus and has value + document.getElementById('search-inputx').addEventListener('focus', function(event) { + var input = event.target; + var dropdown = document.getElementById('dropdown-menu'); + if (input.value.length > 0) { + dropdown.classList.add('show'); + } + }); +} + +templ CssXsampleAutoComplete() { + + + + +} + +templ ShowXSampleScreen(title string, cmp templ.Component, css templ.Component, js templ.Component, + navbarmenu templ.Component, + navbaruser templ.Component, + userprofile templ.Component) { + @layout.CorporateLayout(title, css, js, navbarmenu, navbaruser, userprofile) { + @cmp + } +} diff --git a/views/dev/xsampleautocomplete/xsampleautocomplete_templ.go b/views/dev/xsampleautocomplete/xsampleautocomplete_templ.go new file mode 100644 index 0000000..e659498 --- /dev/null +++ b/views/dev/xsampleautocomplete/xsampleautocomplete_templ.go @@ -0,0 +1,443 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.663 +package dev_xsampleautocomplete + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import ( + "cpone/layout" + "cpone/models" + "strconv" +) + +func EmptyDiv1() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func Selected(data []models.XsampleT_Test) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if len(data) > 0 { + for _, v := range data { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(v.T_TestCode) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views\dev\xsampleautocomplete\xsampleautocomplete.templ`, Line: 17, Col: 18} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(v.T_TestName) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views\dev\xsampleautocomplete\xsampleautocomplete.templ`, Line: 17, Col: 37} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ×") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func ListData(dataList []models.XsampleT_Test) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if len(dataList) > 0 { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, v := range dataList { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(v.T_TestCode) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views\dev\xsampleautocomplete\xsampleautocomplete.templ`, Line: 28, Col: 107} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(v.T_TestName) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views\dev\xsampleautocomplete\xsampleautocomplete.templ`, Line: 28, Col: 126} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
Tidak Ada Data
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func MainAutoComplete() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Typeahead Example with HTMX

Loading...
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = JsCustomAutoComplete().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func TemplJsAutoComplete() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func JsCustomAutoComplete() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_JsCustomAutoComplete_4b2e`, + Function: `function __templ_JsCustomAutoComplete_4b2e(){let selectedItems = []; + + function selectItem(element) { + var container = document.querySelector('.badge-container'); + + // Get the selected item text and id + var itemText = element.textContent; + var itemId = element.getAttribute('data-id'); + + // Check if the item is already selected + if (selectedItems.some(item => item.id === itemId)) { + return; + } + + // Add the item to the selected items list + selectedItems.push({ id: itemId, name: itemText }); + + // Create a badge element + var badge = document.createElement('span'); + badge.className = 'badge badge-primary'; + badge.textContent = itemText; + + // Create a close button + var closeBtn = document.createElement('span'); + closeBtn.className = 'badge badge-light ml-1'; + closeBtn.style.cursor = 'pointer'; + closeBtn.textContent = '×'; + closeBtn.onclick = function() { + container.removeChild(badge); + selectedItems = selectedItems.filter(item => item.id !== itemId); + updateQueryParameter(); + }; + + // Append close button to badge + badge.appendChild(closeBtn); + + // Append the badge to the container + container.appendChild(badge); + + // Clear the input + document.getElementById('search-inputx').value = ''; + + // Hide dropdown + document.getElementById('dropdown-menu').classList.remove('show'); + + // Highlight the selected item in the dropdown + element.classList.add('selected'); + + // Update query parameter + updateQueryParameter(); + } + + function updateQueryParameter() { + var selectedValues = selectedItems.map(item => item.id).join(','); + document.querySelector('input[name="selectedvalue"]').value = selectedValues; + } + + // Display loading indicator when request is in progress + document.body.addEventListener('htmx:configRequest', function(event) { + document.getElementById('loading-indicator').style.display = 'block'; + }); + + document.body.addEventListener('htmx:afterOnLoad', function(event) { + document.getElementById('loading-indicator').style.display = 'none'; + var dropdown = document.getElementById('dropdown-menu'); + if (dropdown.children.length > 0) { + dropdown.classList.add('show'); + dropdown.focus(); + var activeItem = dropdown.querySelector('.active'); + if (activeItem) { + dropdown.scrollTop = activeItem.offsetTop - dropdown.offsetTop; + } + } else { + dropdown.classList.remove('show'); + } + }); + + // Hide the dropdown when clicking outside + document.addEventListener('click', function(event) { + var isClickInside = event.target.classList.contains('search-input') || event.target.classList.contains('badge-container') || event.target.closest('.badge-container'); + if (!isClickInside) { + document.getElementById('dropdown-menu').classList.remove('show'); + } + }); + + // Handle keyboard navigation + document.getElementById('search-inputx').addEventListener('keydown', function(event) { + var dropdownMenu = document.getElementById('dropdown-menu'); + var items = dropdownMenu.querySelectorAll('.dropdown-item'); + var activeItem = dropdownMenu.querySelector('.active'); + + if (event.key === 'ArrowDown') { + event.preventDefault(); // Prevent page scroll + if (!activeItem) { + items[0].classList.add('active'); + } else { + activeItem.classList.remove('active'); + var next = activeItem.nextElementSibling; + if (next) { + next.classList.add('active'); + } else { + items[0].classList.add('active'); + } + } + } + + if (event.key === 'ArrowUp') { + event.preventDefault(); // Prevent page scroll + if (!activeItem) { + items[items.length - 1].classList.add('active'); + } else { + activeItem.classList.remove('active'); + var prev = activeItem.previousElementSibling; + if (prev) { + prev.classList.add('active'); + } else { + items[items.length - 1].classList.add('active'); + } + } + } + + if (event.key === 'Enter' && activeItem) { + selectItem(activeItem); + } + + if (activeItem) { + dropdownMenu.scrollTop = activeItem.offsetTop - dropdownMenu.offsetTop; + } + }); + + // Set the input value and hide the dropdown when an item is clicked + document.body.addEventListener('click', function(event) { + if (event.target.classList.contains('dropdown-item')) { + selectItem(event.target); + } + }); + + // Show dropdown when input gets focus and has value + document.getElementById('search-inputx').addEventListener('focus', function(event) { + var input = event.target; + var dropdown = document.getElementById('dropdown-menu'); + if (input.value.length > 0) { + dropdown.classList.add('show'); + } + }); +}`, + Call: templ.SafeScript(`__templ_JsCustomAutoComplete_4b2e`), + CallInline: templ.SafeScriptInline(`__templ_JsCustomAutoComplete_4b2e`), + } +} + +func CssXsampleAutoComplete() templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var11 := templ.GetChildren(ctx) + if templ_7745c5c3_Var11 == nil { + templ_7745c5c3_Var11 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +func ShowXSampleScreen(title string, cmp templ.Component, css templ.Component, js templ.Component, + navbarmenu templ.Component, + navbaruser templ.Component, + userprofile templ.Component) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var12 := templ.GetChildren(ctx) + if templ_7745c5c3_Var12 == nil { + templ_7745c5c3_Var12 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var13 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + templ_7745c5c3_Err = cmp.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = layout.CorporateLayout(title, css, js, navbarmenu, navbaruser, userprofile).Render(templ.WithChildren(ctx, templ_7745c5c3_Var13), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +}