From 3072bcf0a1d319141fa0967aa1338be6ecb6af53 Mon Sep 17 00:00:00 2001 From: Jachin Rupe Date: Fri, 20 May 2022 12:49:32 -0500 Subject: [PATCH 1/4] Adding some nicer toggles. --- src/Demo.elm | 55 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/Demo.elm b/src/Demo.elm index d8c62ec0..68009255 100644 --- a/src/Demo.elm +++ b/src/Demo.elm @@ -1,8 +1,25 @@ module Demo exposing (main) import Browser -import Html exposing (Attribute, Html, button, div, fieldset, form, input, label, legend, option, select, text) -import Html.Attributes exposing (attribute, for, id, name, type_, value) +import Html + exposing + ( Attribute + , Html + , button + , div + , fieldset + , form + , input + , label + , legend + , option + , select + , table + , td + , text + , tr + ) +import Html.Attributes exposing (attribute, checked, for, id, name, type_, value) import Html.Attributes.Extra import Html.Events exposing (on, onClick) import Html.Events.Extra exposing (onChange) @@ -112,7 +129,7 @@ update msg model = ValidationPass string int else - ValidationFailed string int [ ( "Come on, you can do better than asdf", "error" ) ] + ValidationFailed string int [ ( "Come on, you can do better than 'asdf'", "error" ) ] in ( { model | customValidationResult = customValidationResult }, Cmd.none ) @@ -293,8 +310,34 @@ view model = , form [] [ fieldset [] [ legend [] [ text "Input Methods" ] - , button [ onClick ToggleAllowCustomValues, type_ "button" ] [ text "toggle allow custom values" ] - , button [ onClick ToggleMultiSelect, type_ "button" ] [ text "toggle multi select" ] + , table [] + [ tr [] + [ td [] [ text "Allow Custom Options" ] + , td [] + [ if model.allowCustomOptions then + text "ON" + + else + text "OFF" + ] + , td [] + [ button [ onClick ToggleAllowCustomValues, type_ "button" ] [ text "toggle" ] + ] + ] + , tr [] + [ td [] [ text "Multi Select" ] + , td [] + [ if model.allowMultiSelect then + text "ON" + + else + text "OFF" + ] + , td [] + [ button [ onClick ToggleMultiSelect, type_ "button" ] [ text "toggle" ] + ] + ] + ] ] , fieldset [] [ legend [] @@ -305,6 +348,7 @@ view model = , name "output-style" , id "output-style-custom-html" , value "custom-html" + , checked (model.outputStyle == "custom-html") , onChange ChangeOutputStyle ] [] @@ -314,6 +358,7 @@ view model = , name "output-style" , id "output-style-datalist" , value "datalist" + , checked (model.outputStyle == "datalist") , onChange ChangeOutputStyle ] [] From 4a4e19aab1cde4ec2610770dd2bb57d404db7216 Mon Sep 17 00:00:00 2001 From: Jachin Rupe Date: Fri, 20 May 2022 14:20:52 -0500 Subject: [PATCH 2/4] Better valueChanged events. Include data about validity. Add a new event for when the value is invalid. --- src/Demo.elm | 48 ++++++++++++++-------------- src/Main.elm | 34 +++++++++++--------- src/Ports.elm | 30 +++++++++++++++--- src/gen/filter-worker-elm.js | 36 ++++++++++++++------- src/gen/much-select-template.js | 2 +- src/much-select.js | 56 +++++++++++++++++++++------------ 6 files changed, 130 insertions(+), 76 deletions(-) diff --git a/src/Demo.elm b/src/Demo.elm index 68009255..5a101031 100644 --- a/src/Demo.elm +++ b/src/Demo.elm @@ -41,7 +41,7 @@ type alias Model = type Msg = MuchSelectReady - | ValueChanged MuchSelectValue + | ValueChanged (List MuchSelectValue) | ValueCleared | OptionSelected | BlurOrUnfocusedValueChanged String @@ -169,6 +169,28 @@ onReady = on "muchSelectReady" (Json.Decode.succeed MuchSelectReady) +type alias MuchSelectValue = + { value : String, label : String } + + +valueDecoder : Json.Decode.Decoder MuchSelectValue +valueDecoder = + Json.Decode.map2 + MuchSelectValue + (Json.Decode.field "value" Json.Decode.string) + (Json.Decode.field "label" Json.Decode.string) + + +onValueChanged : Attribute Msg +onValueChanged = + on "valueChanged" (Json.Decode.map ValueChanged (Json.Decode.at [ "detail", "values" ] (Json.Decode.list valueDecoder))) + + +onValueCleared : Attribute Msg +onValueCleared = + on "valueCleared" (Json.Decode.succeed ValueCleared) + + onOptionSelected : Attribute Msg onOptionSelected = on "optionSelected" (Json.Decode.succeed OptionSelected) @@ -240,28 +262,6 @@ outputStyleAttribute string = attribute "output-style" string -type alias MuchSelectValue = - { value : String, label : String } - - -valueDecoder : Json.Decode.Decoder MuchSelectValue -valueDecoder = - Json.Decode.map2 - MuchSelectValue - (Json.Decode.field "value" Json.Decode.string) - (Json.Decode.field "label" Json.Decode.string) - - -singleValueChangedAttribute : Attribute Msg -singleValueChangedAttribute = - on "valueChanged" (Json.Decode.map ValueChanged (Json.Decode.at [ "detail", "value" ] valueDecoder)) - - -onValueCleared : Attribute Msg -onValueCleared = - on "valueCleared" (Json.Decode.succeed ValueCleared) - - view : Model -> Html Msg view model = let @@ -279,7 +279,7 @@ view model = , allowCustomOptionsAttribute model.allowCustomOptions , multiSelectAttribute model.allowMultiSelect , outputStyleAttribute model.outputStyle - , singleValueChangedAttribute + , onValueChanged , onCustomValidationRequest , onCustomValueSelected , onBlurOrUnfocusedValueChanged diff --git a/src/Main.elm b/src/Main.elm index ad5f2db9..d2f67604 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -121,6 +121,7 @@ import Ports , inputBlurred , inputFocused , inputKeyUp + , invalidValue , loadingChangedReceiver , maxDropdownItemsChangedReceiver , muchSelectIsReady @@ -426,7 +427,7 @@ update msg model = } |> updateModelWithChangesThatEffectTheOptionsWhenTheSearchStringChanges , Cmd.batch - [ makeCommandMessagesWhenValuesChanges updatedOptions (Just optionValue) + [ makeCommandMessagesWhenValuesChanges (selectedOptions updatedOptions) (Just optionValue) , blurInput () ] ) @@ -438,7 +439,7 @@ update msg model = } |> updateModelWithChangesThatEffectTheOptionsWhenTheSearchStringChanges , Cmd.batch - [ makeCommandMessagesWhenValuesChanges updatedOptions (Just optionValue) + [ makeCommandMessagesWhenValuesChanges (selectedOptions updatedOptions) (Just optionValue) , focusInput () ] ) @@ -706,7 +707,7 @@ update msg model = } |> updateModelWithChangesThatEffectTheOptionsWhenTheSearchStringChanges , Cmd.batch - [ makeCommandMessagesWhenValuesChanges updatedOptions (Just optionValue) + [ makeCommandMessagesWhenValuesChanges (selectedOptions updatedOptions) (Just optionValue) , makeCommandMessagesForUpdatingOptionsInTheWebWorker model.searchString , Task.perform (\_ -> @@ -906,7 +907,7 @@ update msg model = } |> updateModelWithChangesThatEffectTheOptionsWhenTheSearchStringChanges , Cmd.batch - [ makeCommandMessagesWhenValuesChanges updatedOptions maybeHighlightedOptionValue + [ makeCommandMessagesWhenValuesChanges (selectedOptions updatedOptions) maybeHighlightedOptionValue , makeCommandMessagesForUpdatingOptionsInTheWebWorker model.searchString , blurInput () ] @@ -919,7 +920,7 @@ update msg model = } |> updateModelWithChangesThatEffectTheOptionsWhenTheSearchStringChanges , Cmd.batch - [ makeCommandMessagesWhenValuesChanges updatedOptions maybeHighlightedOptionValue + [ makeCommandMessagesWhenValuesChanges (selectedOptions updatedOptions) maybeHighlightedOptionValue , makeCommandMessagesForUpdatingOptionsInTheWebWorker model.searchString , focusInput () ] @@ -1006,7 +1007,9 @@ update msg model = } |> updateModelWithChangesThatEffectTheOptionsWhenTheSearchStringChanges , Cmd.batch - [ valueChanged (selectedOptionsToTuple updatedOptions) + [ valueChanged (updatedOptions |> selectedOptions |> Ports.optionsEncoder) + + -- todo optionDeselected , focusInput () ] ) @@ -1145,7 +1148,7 @@ deselectOption model option = } |> updateModelWithChangesThatEffectTheOptionsWhenTheSearchStringChanges , Cmd.batch - [ makeCommandMessagesWhenValuesChanges updatedOptions Nothing + [ makeCommandMessagesWhenValuesChanges (selectedOptions updatedOptions) Nothing , makeCommandMessagesForUpdatingOptionsInTheWebWorker model.searchString ] ) @@ -1154,21 +1157,22 @@ deselectOption model option = clearAllSelectedOption : Model -> ( Model, Cmd Msg ) clearAllSelectedOption model = let - deselectedItems = + deselectedOptions : List Option + deselectedOptions = if List.isEmpty <| selectedOptionsToTuple model.options then -- no deselected options [] else -- an option has been deselected. return the deselected value as a tuple. - selectedOptionsToTuple model.options + model.options deselectEventCmdMsg = - if List.isEmpty deselectedItems then + if List.isEmpty deselectedOptions then Cmd.none else - optionDeselected deselectedItems + optionDeselected (Ports.optionsEncoder deselectedOptions) newOptions = deselectAllOptionsInOptionsList model.options @@ -2661,10 +2665,10 @@ makeCommandMessagesWhenValuesChanges selectedOptions maybeSelectedValue = let valueChangeCmd = if OptionsUtilities.allOptionsAreValid selectedOptions then - valueChanged (selectedOptionsToTuple selectedOptions) + valueChanged (Ports.optionsEncoder selectedOptions) else - Cmd.none + invalidValue (Ports.optionsEncoder selectedOptions) selectedCustomOptions = customSelectedOptions selectedOptions @@ -2693,7 +2697,7 @@ makeCommandMessagesWhenValuesChanges selectedOptions maybeSelectedValue = case findOptionByOptionValue selectedValue selectedOptions of Just option -> if Option.isValid option then - optionSelected (Option.optionToValueLabelTuple option) + optionSelected (Ports.optionEncoder option) else Cmd.none @@ -2753,7 +2757,7 @@ makeCommandMessageForInitialValue selectedOptions = Cmd.none selectionOptions_ -> - initialValueSet (selectedOptionsToTuple selectionOptions_) + initialValueSet (Ports.optionsEncoder selectionOptions_) type alias Flags = diff --git a/src/Ports.elm b/src/Ports.elm index a1f6fdd1..192dee9d 100644 --- a/src/Ports.elm +++ b/src/Ports.elm @@ -13,14 +13,17 @@ port module Ports exposing , inputBlurred , inputFocused , inputKeyUp + , invalidValue , loadingChangedReceiver , maxDropdownItemsChangedReceiver , muchSelectIsReady , multiSelectChangedReceiver , multiSelectSingleItemRemovalChangedReceiver , optionDeselected + , optionEncoder , optionSelected , optionSortingChangedReceiver + , optionsEncoder , optionsReplacedReceiver , optionsUpdated , outputStyleChangedReceiver @@ -48,6 +51,8 @@ port module Ports exposing import Json.Decode import Json.Encode +import Option exposing (Option) +import OptionLabel port muchSelectIsReady : () -> Cmd msg @@ -56,10 +61,13 @@ port muchSelectIsReady : () -> Cmd msg port errorMessage : String -> Cmd msg -port valueChanged : List ( String, String ) -> Cmd msg +port valueChanged : Json.Encode.Value -> Cmd msg -port initialValueSet : List ( String, String ) -> Cmd msg +port invalidValue : Json.Encode.Value -> Cmd msg + + +port initialValueSet : Json.Encode.Value -> Cmd msg port customOptionSelected : List String -> Cmd msg @@ -68,10 +76,24 @@ port customOptionSelected : List String -> Cmd msg port valueCleared : () -> Cmd msg -port optionSelected : ( String, String ) -> Cmd msg +port optionSelected : Json.Encode.Value -> Cmd msg + + +port optionDeselected : Json.Encode.Value -> Cmd msg -port optionDeselected : List ( String, String ) -> Cmd msg +optionsEncoder : List Option -> Json.Encode.Value +optionsEncoder options = + Json.Encode.list optionEncoder options + + +optionEncoder : Option -> Json.Encode.Value +optionEncoder option = + Json.Encode.object + [ ( "value", Json.Encode.string (Option.getOptionValueAsString option) ) + , ( "label", Json.Encode.string (Option.getOptionLabel option |> OptionLabel.optionLabelToString) ) + , ( "is_valid", Json.Encode.bool (Option.isValid option) ) + ] port inputKeyUp : String -> Cmd msg diff --git a/src/gen/filter-worker-elm.js b/src/gen/filter-worker-elm.js index ba709569..b78b8d62 100644 --- a/src/gen/filter-worker-elm.js +++ b/src/gen/filter-worker-elm.js @@ -3556,6 +3556,7 @@ var $author$project$Option$setOptionSearchFilter = F2( return option; } }); +var $elm$core$String$contains = _String_contains; var $author$project$OptionSearchFilter$descriptionHandicap = function (score) { return (score < 5) ? 5 : $elm$core$Basics$floor(score * 1.25); }; @@ -3650,6 +3651,17 @@ var $author$project$Option$optionGroupToString = function (optionGroup) { return ''; } }; +var $elm$core$String$toLower = _String_toLower; +var $author$project$OptionLabel$optionLabelToSearchString = function (optionLabel) { + var string = optionLabel.a; + var maybeCleanString = optionLabel.b; + if (!maybeCleanString.$) { + var cleanString = maybeCleanString.a; + return cleanString; + } else { + return $elm$core$String$toLower(string); + } +}; var $author$project$OptionLabel$optionLabelToString = function (optionLabel) { var label = optionLabel.a; return label; @@ -4072,7 +4084,6 @@ var $author$project$OptionSearcher$groupMatch = F2( needle, hay); }); -var $elm$core$String$toLower = _String_toLower; var $author$project$Option$optionDescriptionToSearchString = function (optionDescription) { if (!optionDescription.$) { var description = optionDescription.a; @@ -4095,16 +4106,6 @@ var $author$project$Option$optionGroupToSearchString = function (optionGroup) { return ''; } }; -var $author$project$OptionLabel$optionLabelToSearchString = function (optionLabel) { - var string = optionLabel.a; - var maybeCleanString = optionLabel.b; - if (!maybeCleanString.$) { - var cleanString = maybeCleanString.a; - return cleanString; - } else { - return $elm$core$String$toLower(string); - } -}; var $author$project$OptionSearcher$simpleMatch = F2( function (needle, hay) { return A4( @@ -4424,10 +4425,21 @@ var $author$project$OptionSearcher$updateSearchResultInOption = F2( $author$project$OptionSearchFilter$descriptionHandicap(searchResult.bf.aX), $author$project$OptionSearchFilter$groupHandicap(searchResult.bn.aX) ]))); + var cappedBestScore = (bestScore > 100) ? (A2( + $elm$core$String$contains, + $elm$core$String$toLower( + $author$project$SearchString$toString(searchString)), + $elm$core$String$toLower( + $author$project$OptionLabel$optionLabelToSearchString( + $author$project$Option$getOptionLabel(option)))) ? (($elm$core$String$length( + $author$project$SearchString$toString(searchString)) < 3) ? bestScore : (($elm$core$String$length( + $author$project$SearchString$toString(searchString)) < 4) ? 20 : (($elm$core$String$length( + $author$project$SearchString$toString(searchString)) < 5) ? 15 : (($elm$core$String$length( + $author$project$SearchString$toString(searchString)) < 6) ? 10 : bestScore)))) : bestScore) : bestScore; return A2( $author$project$Option$setOptionSearchFilter, $elm$core$Maybe$Just( - A5($author$project$OptionSearchFilter$new, totalScore, bestScore, labelTokens, descriptionTokens, groupTokens)), + A5($author$project$OptionSearchFilter$new, totalScore, cappedBestScore, labelTokens, descriptionTokens, groupTokens)), option); }); var $author$project$OptionSearcher$updateOptionsWithSearchString = F3( diff --git a/src/gen/much-select-template.js b/src/gen/much-select-template.js index 8f671629..fa341b65 100644 --- a/src/gen/much-select-template.js +++ b/src/gen/much-select-template.js @@ -6,7 +6,7 @@ const getMuchSelectTemplate = (styleTag) => {