behavior Datepicker
    init
        set :dp to createCalendar(me, me)
    end
end
behavior DatepickerInput
    init immediately
        set :dialog to first <#datepicker/>
        set :content to first <.modal-content/> in :dialog
        set :name to my @data-name
        set :tpl to first <[data-role="template"]/> in me
        set :dates to first <[data-role="dates"]/> in me
        if :tpl
            set @tabindex of :tpl to '0'
            put :tpl as HTML at the start of :dates
            put :tpl as HTML at the end of :dates
            set :from to first <[data-role="template"]/> in :dates
            set :to to last <[data-role="template"]/> in :dates
            remove :tpl
            set @data-role of :from to 'from'
            set @data-role of :to to 'to'
        end
        set :fromInput to <[data-role="input-from"]/> in me
        set :toInput to <[data-role="input-to"]/> in me
    end

    init
        get createDateRange('+1d', '+1d')
        set :initial to it
        trigger setDates(dateFromStr: :initial.from, dateToStr: :initial.to)
    end

    on dismiss
        send closeModal to :dialog
    end

    on setDates(dateFromStr, dateToStr)
        set value of :fromInput to dateFromStr
        if :from
            call renderFormat(dateFromStr, :from)
        end
        set value of :toInput to dateToStr
        if :to
            call renderFormat(dateToStr, :to)
        end
    end

    on accept(dateFromStr, dateToStr)
        trigger setDates(dateFromStr: dateFromStr, dateToStr: dateToStr)
        trigger dismiss
    end

    on click
        send openModal to :dialog
        set :calendar to createCalendar(me, :content)
    end

    on keyup[key=="Enter"] from me
        send openModal to :dialog
        set :calendar to createCalendar(me, :content)
    end
end
behavior ListFilter
    init immediately
        set :nav to first <[data-role="filter-nav"]/> in me
        set :list to first <[data-role="filter-list"]/> in me
        set :navItems to <[data-action="filter"]/> in :nav
        set :listItems to :list.children

        set :sections to <[data-role="list-section"]/>
        get document.querySelectorAll('[data-role="filter-list"] > *')
        set :listItems to it
    end

    init
        get getHashQueryVariable('tag')
        set :tag to it
        if :tag
            setFilter(:tag)
        else
            set :btn to the first <[data-action="filter"][data-tag="*"]/> in :nav
            if :btn
                take .active from :navItems for :btn
                take [@aria-current=true] from :navItems for :btn
            end
        end
    end

    def setFilter(tag)
        set :btn to the first <[data-action="filter"][data-tag="${tag}"]/> in :nav

        take .active from :navItems for :btn
        take [@aria-current=true] from :navItems for :btn

        if :tag is '*'
            call setHashQueryVariable('tag', null)
            if :listItems
                remove .hide from :listItems
                remove @hidden from :listItems
                if :list
                    send 'zuu:list:filter' to :list
                end
            end
            remove @hidden from :sections
            return true
        end

        if :listItems
            add .hide to :listItems
            set @hidden of :listItems to ''
            get filterList(:listItems, tag) then set :visible to it
            remove .hide from :visible
            remove @hidden from :visible

            if :list
                send 'zuu:list:filter' to :list
            end
        end

        for s in :sections
            set :sectionList to first <[data-role="filter-list"]/> in s
            if :sectionList
                set :hidden to <[hidden]/> in :sectionList
                set :count to @data-items of :sectionList
                if :hidden.length >= :count * 1
                    set @hidden of s to ''
                else
                    remove @hidden from s
                end
            end
        end

        call setHashQueryVariable('tag', tag)
    end

    on 'zuu:action:filter'
        set :tag to @data-tag of event.target
        setFilter(:tag)
    end
end
behavior Form
    def showConsents()
        send openModal to :modal

        set :modalForm to the first <form/> in :modal
        set @hidden of :status to ''
        remove @hidden from :modalForm
        remove @hidden from :actions
        put :consents into :modalForm

        for chk in :consentCheckboxes
            remove @disabled from chk
        end

        set :consentConfirm to true
    end

    def submitConsentCheck()
        get me.checkValidity() then set :valid to it
        if not :valid
            call me.reportValidity()
        else
            if :mode is 'modal'
                showConsents()
            else
                trigger submit
            end
        end
    end

    def handleConfirm()
        get me.checkValidity() then set :valid to it
        if :valid
            get :modalForm.checkValidity() then set :consentValid to it
            if :consentValid
                put :consents into :container
                set :consentConfirm to false
                trigger submit
            else
                call :modalForm.reportValidity()
            end
        else
            send closeModal to :modal
            call me.reportValidity()
        end
    end

    init immediately
        set :modal to the first <#confirm/>
        set :status to the first <[data-role="form-status"]/> in :modal
        set :actions to the first <[data-role="form-actions"]/> in :modal

        set :container to the first <[data-role="form-consents-container"]/> in me

        if :container
            set :mode to @data-display of :container

            if :mode is 'modal'
                set :consents to the first <[data-role="form-consents"]/> in me
                set :consentCheckboxes to <input/> in :consents
                for chk in :consentCheckboxes
                    set @disabled of chk to ''
                end
            else
                remove @hidden from :container
            end
        end
    end

    on click from <[data-action="submit"]/> in me
        halt the event
        submitConsentCheck()
    end

    on confirm from :modal
        if :consentConfirm
            handleConfirm()
        end
    end

    def toggleStatus(status)
        remove @hidden from :status
        set :statuses to <[data-status]/> in :status
        for s in :statuses
            if @data-status of s is status
                remove @hidden from s
            else
                set @hidden of s to ''
            end
        end
    end

    on submit
        send openModal to :modal
        if :modalForm
            set @hidden of :modalForm to ''
        end
        set @aria-busy of :modal to 'true'
        remove @hidden from :status
        set @aria-live of :status to 'polite'
        set @hidden of :actions to ''
        get serializeForm(me)
        set :data to it
        set :action to my @action
        toggleStatus('sending')
        fetch `${:action}` as json with method:"POST",body: :data
        if result.status
            set :result to it
            toggleStatus('success')
            call clearForm(me)
        else
            set :result to it
            toggleStatus('error')
            call alert(:result.error)
        end
    end

    on dismiss from :modal
        remove @aria-live from :status
        if :consentConfirm
            wait 200ms
            put :consents into :container
            for chk in :consentCheckboxes
                set @disabled of chk to ''
            end
        end
    end
end
behavior Guestpicker
    init immediately
        get generateId('guests')
        set :gid to it

        set :msg to first <[data-role="msg"] /> in me
        if not :msg
            append `<div data-role="msg">Określ wiek dzieci</div>` to me
        end
        set :ages to first <[data-role="ages"]/> in me
        if not :ages
            append `<div data-role="ages"/>` to me
        end
        set :btn to first <[data-action="submit"] /> in me
        if not :btn
            append `<button data-action="submit">Zatwierdź</button>` to me
        end

        set :msg to first <[data-role="msg"]/> in me
        set :ages to first <[data-role="ages"]/> in me
        set :state to []

        add .guest-picker to me
    end

    init
        if @data-id
            get document.getElementById(@data-id)
            set :target to it
        end
        wait 1ms
        trigger submit(close: false)
    end

    def createAgeInput(id)
        make an <input/> called input
        set @required of input to ''
        set @type of input to "number"
        set @min of input to 0
        set @max of input to 14
        set @id of input to id
        set @name of input to 'ages[]'
        return input
    end

    def createAgeSelect(id)
        make a <select/> called select
        set @required of select to ''
        set @id of select to id
        set @name of select to 'ages[]'
        set @data-script of select to "install Select(size: 'sm')"
        set :j to 0
        append `<option value="" disabled selected>Wybierz</option>` to select
        repeat 15 times
            if :j is 0
                set :label to '< 1 rok'
            else
                set :label to countStr(:j, 'age')
            end
            append `<option value="${:j}">${:label}</option>` to select
            set :j to :j + 1
        end
        return select
    end

    on update(value) from <[data-name="children"]/> in me
        set textContent of :ages to ''
        set :i to 0
        if value
            remove @hidden from :msg
            repeat value times
                set :ageId to `${:gid}_${:i}`
                set :input to createAgeSelect(:ageId)
                make a <div/> called :ageInput
                add .age-input to :ageInput
                append `<label for="${:ageId}">Wiek ${:i+1}</label>`
                append :input as HTML
                put it at the end of :ages
                set :i to :i + 1
            end
        else
            set @hidden of :msg to ''
        end
    end

    on click from <[data-action="submit"]/> in me
        halt the event
        trigger submit(close: true)
    end

    on submit(close)
        halt the event
        call validateDiv(me) then set :isValid to it
        call serializeDiv(me) then set :result to it
        if :target and :isValid
            if close
                send closeAndFocus to :target
            end
            send update(value: :result) to :target
        end
    end
end
behavior GuestpickerControl
    init immediately
        set :input to first <[data-script="install GuestpickerInput"]/> in me
    end

    on update(value)
        halt the event
        send update(value: value) to :input
    end
end
behavior GuestpickerInput
    init immediately
        append `
            <span data-role="label"></span>
            <input name="adults" type="hidden" />
            <input name="children" type="hidden" />
            <input name="ages" type="hidden" />
        ` to me
        set :adults to first <[name="adults"]/> in me
        set :children to first <[name="children"]/> in me
        set :ages to first <[name="ages"]/> in me
        set :label to first <[data-role="label"]/> in me
    end

    on update(value)
        halt the event
        set @value of :adults to value.adults
        set @value of :children to value.children
        if value.ages
            set @value of :ages to value.ages.join(',')
        end
        call guestsToString(value)
        set :str to it
        set textContent of :label to :str
    end
end
behavior StepInput
    init immediately
        if not @id
            get generateId('guests')
            set @id to it
        end

        set :min to @data-min * 1
        if not :min
            set :min to 0
        end

        add .step-input to me
        set :inputId to `${@id}_input`
        set :label to first <label/> in me
        set @for of :label to :inputId
        set :value to :min
        set :name to @data-name

        append `<div class="step-control">
            <button data-action="dec">-</button>
            <span data-role="value"></span>
            <button data-action="inc">+</button>
            <input hidden />
        </div>` to me

        set :input to first <input/> in me
        set :valueDisplay to <[data-role="value"]/> in me
        set @id of :input to :inputId
        set @type of :input to 'number'
        set @min of :input to :min
        set @name of :input to :name
        set @value of :input to
    end

    init
        trigger update(value: :value)
    end

    on update
        set @value of :input to :value
        set textContent of :valueDisplay to :value
        if :value <= :min
            set @disabled of <[data-action="dec"]/> in me to ''
        else
            remove @disabled from <[data-action="dec"]/> in me
        end
    end

    on click from <[data-action="dec"]/> in me
        if :value > 0
            set :value to :value - 1
            trigger update(value: :value)
        end
    end

    on click from <[data-action="inc"]/> in me
        set :value to :value + 1
        trigger update(value: :value)
    end
end
behavior ActionHandler
    init
        log '[ActionHandler] init'
    end

    on click from <[data-action]/> in me
        set :target to the closest <[data-action]/> to event.target
        set :action to @data-action of :target
        log '[ActionHandler] click', :action, event
        call dispatchAction(:target, :action, {})
    end

    on keydown from <div[role="button"]/> in me
        if event.code == 'Enter' or event.code == 'Space'
            set :target to the closest <[data-action]/> to event.target
            if :target
                set :action to @data-action of :target
                call dispatchAction(:target, :action, {})
                halt the event
            end
        end
    end

    on zuu:action:book
    end

end
behavior Modal(trigger)
    init
        set :root to me
    end

    on openModal
        add .is-open to :root
        call me.showModal()
    end

    on closeModal
        remove .is-open from :root
        call me.close() then settle
        trigger dismiss
    end

    on toggleModal
        toggle .is-open on :root
    end

    on click[target==me]
        trigger closeModal
    end

    on click from <[data-action="dismiss"]/> in me
        halt the event
        trigger closeModal
    end

    on click from <[data-action="confirm"]/> in me
        halt the event
        trigger confirm
    end

    on click from trigger
        halt the event
        set url to @data-href of event.currentTarget
        trigger fetchModal(url: url)
    end

    on keyup[key=="Escape"] from window
        trigger closeModal
    end

    on fetchModal(url)
        halt the event
        trigger openModal
        add .is-loading to :root
        set @aria-busy to 'true'
        set :content to the first <.modal-content/> in me
        fetch `${url}` as html
        call addPageContentTo(:content, it)
        call window._hyperscript.processNode(:content)
        remove .is-loading
        remove @aria-busy
    end
end
js
    let popups = [];
    function registerPopup(id) {
        popups.push(id);
    }
    function deregisterPopup(id) {
        popups = popups.filter(p => p !== id);
    }
    function isOnTop(id) {
        console.log(popups);
        return popups[popups.length - 1] === id;
    }
    return {registerPopup, deregisterPopup, isOnTop}
end

behavior Popover
    init immediately
        if not @id
            get generateId('popover')
            set @id to it
        end

        set :tid to `${@id}_toggle`
        set :cid to `${@id}_content`

        set :content to first <[data-role="content"]/> in me
        set :btn to first <[data-role="toggle"]/> in me

        add .popover-content to :content

        put :content at the end of <body/>

        set @id of :content to :cid
        set @id of :btn to :tid
        set @data-id of :content to @id

        set @role of :btn to 'button'
        set @tabindex of :btn to 0
        set @aria-controls of :btn to :cid
        set @aria-labelledby of :content to :tid
        set @role of :content to 'region'
        set @tabindex of :content to 0

        add .fade to :content
        set :popover to me
    end

    init
        --- trigger close
        set @hidden of :content to ''
        set @aria-expanded of :btn to false
        set :isOpen to false
    end

    on click from <[data-role="toggle"]/> in me
        call console.log('[toggle] click from toggle')
        trigger toggle
    end

    on keydown[key=="Enter"] from <[data-role="toggle"]/> in me
        call console.log('[toggle] keyup Enter from btn')
        trigger toggle
    end

    on keydown[key=="Escape"] from :content
        call console.log('[close] keyup Esc from content')
        trigger closeAndFocus
    end

    on click from window
        if :isOpen
            get isOrIsChildOf(event.target, me) then set :isToggle to it
            get isOrIsChildOf(event.target, :content) then set :isContent to it
            get isOnTop(@id) then set :top to it
            if not :isToggle and not :isContent and :top
                call console.log('[close] click outside')
                trigger close
            end
        end
    end

    on toggle
        if :isOpen
            trigger closeAndFocus
        else
            trigger open
        end
    end

    on open
        remove @hidden from :content
        set @aria-expanded of :btn to true
        set :isOpen to true
        call positionRelativeTo(:btn, :content)
        call :content.focus()
        remove .fade from :content then settle
        wait 1ms
        call registerPopup(@id)
    end

    on close
        call deregisterPopup(@id)
        add .fade to :content then settle
        set @hidden of :content to ''
        set @aria-expanded of :btn to false
        set :isOpen to false
        call console.log('[close] Popover move focus to toggle')
    end

    on closeAndFocus
        trigger close
        call :btn.focus()
    end
end
js
    function setSelectValue(select, value) {
        select.selectedIndex = value;
        select.dispatchEvent(new Event('change'));
    }
end

behavior Select(size)
    init immediately
        make a <div/> called container
        put it after me
        make a <div/> called toggle
        add .input-base to toggle
        if size is 'sm'
            add .input-base-sm to toggle
        end
        set @data-role of toggle to 'toggle'
        set textContent of toggle to 'Wybierz'
        put it at the end of container
        make <div/> called content
        set @data-role of content to 'content'
        add .select-list to content
        put it at the end of container
        call createWebfontIcon(toggle, 'fh-chevron-down', 'dropdown-arrow')
        put me at the end of container
        set @data-script of container to 'install Popover'
        set @hidden to ''
        set options to <option:not([disabled])/> in me
        make an <ul/> called list
        repeat for o in options index i
            append `<li data-role="option" data-index="${i}" data-value="${o.value}">${o.innerText}</li>` to list
        end
        put list into content
        set :toggle to toggle
        set :popover to container
        set :content to content
    end

    on click from <[data-role="option"]/> in :content
        halt the event
        set value to @data-index of event.target
        call setSelectValue(me, value)
        send close to :popover
    end

    on change
        get me.options[me.selectedIndex] then set :option to it
        set textContent of :toggle to :option.textContent
    end

    on reportValidity
        add .invalid to :toggle
    end

    on click from :popover
        remove .invalid from :toggle
    end
end