ivelum / djangoql

Advanced search language for Django
MIT License
1.02k stars 89 forks source link

Not working with Unfold Admin #116

Open intp1 opened 7 months ago

intp1 commented 7 months ago

This app is amazing. Anyway, while building a practical project, the original Django admin is quite possibly replaced by some customizable admins, so I guess integrating djangoql with those admins is very important and useful. So far as I tested, it seems like that simpleui works fine with djangoql, but Unfold Admin doesn't. Any filter commands with djangoql search out with empty result. I wonder if there is an easy way to integrate with Unfold Admin, otherwise I might have to give up this wonderful app and find a compatible replacement for smart filtering. Thanks.

intp1 commented 7 months ago

In case a detail report is needed: As use djangoql in original django admin to filter with condition of id = 1, a url with arguments of .../?q-l=on&q=id+%3D+1 is created automatically, which return the right result. Instead in Unfold Admin, the same condition produces url with arguments like .../?q=id%20=%201, which return an empty result. By the way, copy the right url of .../?q-l=on&q=id+%3D+1 to Unfold Admin could also get the right result.

BitTheByte commented 2 months ago

+1 on this

dipespandey commented 4 days ago

I got it to work by adding custom javascript to explicitly add the q-l parameter to the url parameter.

document.addEventListener('DOMContentLoaded', function () {
    const form = document.querySelector('#changelist-form')
    const searchButton = document.querySelector('#searchbar-submit')
    const searchInput = form.querySelector('textarea[name="q"]')
    const toggleCheckbox = form.querySelector('.djangoql-toggle')
    const actionButton = form.querySelector('button[name="action"]') // Detect the action button

    if (searchButton) {
        // Replace the search button with a clone to remove existing listeners
        const newSearchButton = searchButton.cloneNode(true)
        searchButton.parentNode.replaceChild(newSearchButton, searchButton)

        // Handle search button clicks
        newSearchButton.addEventListener('click', function (e) {
            e.preventDefault() // Prevent default form submission
            e.stopImmediatePropagation() // Prevent other handlers

            // Perform search
            performSearch()
        })
    }

    // Dynamically update the URL whenever the search input or toggle state changes
    searchInput.addEventListener('input', updateURL)
    if (toggleCheckbox) {
        toggleCheckbox.addEventListener('change', updateURL)
    }

    // Handle Enter key press in the search bar
    searchInput.addEventListener('keydown', function (e) {
        if (e.key === 'Enter') {
            e.preventDefault() // Prevent the default behavior of the Enter key (e.g., adding a new line)
            performSearch() // Trigger search
        }
    })

    // Allow native submit for non-search actions
    if (form) {
        form.addEventListener('submit', function (e) {
            // Check the submitter button
            const submitter = e.submitter || document.activeElement
            if (submitter && submitter.id === 'searchbar-submit') {
                // Handle search submit
                e.preventDefault()
                e.stopImmediatePropagation()
                performSearch()
            } else {
                // Allow default submission for actions
                return
            }
        })
    }

    // Function to perform the search
    function performSearch() {
        const searchTerm = searchInput ? searchInput.value.trim() : ''
        const toggleState = toggleCheckbox && toggleCheckbox.checked ? 'on' : 'off'

        // Construct query parameters
        const params = new URLSearchParams()
        if (searchTerm) {
            params.append('q', searchTerm)
        }
        params.append('q-l', toggleState)

        // Preserve existing query parameters except 'q' and 'q-l'
        const existingParams = new URLSearchParams(window.location.search)
        existingParams.forEach((value, key) => {
            if (key !== 'q' && key !== 'q-l') {
                params.append(key, value)
            }
        })

        // Redirect to the new URL
        const targetUrl = `${window.location.pathname}?${params.toString()}`
        console.log('Redirecting to:', targetUrl)

        // Redirect
        window.location.href = targetUrl
    }

    // Function to update the URL dynamically (without redirecting)
    function updateURL() {
        const searchTerm = searchInput ? searchInput.value.trim() : ''
        const toggleState = toggleCheckbox && toggleCheckbox.checked ? 'on' : 'off'

        // Construct query parameters
        const params = new URLSearchParams()
        if (searchTerm) {
            params.append('q', searchTerm)
        }
        params.append('q-l', toggleState)

        // Preserve existing query parameters except 'q' and 'q-l'
        const existingParams = new URLSearchParams(window.location.search)
        existingParams.forEach((value, key) => {
            if (key !== 'q' && key !== 'q-l') {
                params.append(key, value)
            }
        })

        // Update the browser's URL without reloading the page
        const targetUrl = `${window.location.pathname}?${params.toString()}`
        window.history.replaceState({}, '', targetUrl)
    }
})