Yet another SelectList implementation
A SelectList is a non-empty list which always has exactly one element selected. It is an example of a list zipper.
Inspired by these modules
selectedMap
is the feature function in this package.
Use selectedMap
in view.
view : SelectList String -> Html Msg
view selectList =
ul [] <|
SelectList.selectedMap
(\position item ->
li [ onClick (Set item) ]
[ text <| toString <| SelectList.index item
, toString <| SelectList.selected item
]
)
selectList
Types.SelectList a
A nonempty list which always has exactly one element selected.
fromLists : List a -> a -> List a -> SelectList a
Create a SelectList
.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selected
== 4
fromList : List a -> Maybe (SelectList a)
Create a SelectList
if list has elements.
If empty, Nothing
.
fromList [] == Nothing
fromList [ 2, 3, 4 ] == Just (fromLists [] 2 [ 3, 4 ])
singleton : a -> SelectList a
Create a SelectList
containing exactly one element.
singleton 3 == fromLists [] 3 []
toTuple : SelectList a -> ( List a, a, List a )
Destruct SelectList
.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> toTuple
== ( 1, 2, 3 ) 4 ( 5, 6 )
selected : SelectList a -> a
Return the selected element.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selected
== 4
listAfter : SelectList a -> List a
Return the elements after the selected element.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> listAfter
== [ 5, 6 ]
listBefore : SelectList a -> List a
Return the elements before the selected element.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> listBefore
== [ 1, 2, 3 ]
toList : SelectList a -> List a
Destruct SelectList
.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> toList
== [ 1, 2, 3, 4, 5, 6 ]
isHead : SelectList a -> Basics.Bool
Check if the selected element is first element.
fromLists [] 4 [ 5, 6 ]
|> isHead
== True
isLast : SelectList a -> Basics.Bool
Check if the selected element is last element.
fromLists [ 1, 2, 3 ] 4 []
|> isLast
== True
isSingle : SelectList a -> Basics.Bool
Check if the selected element is only element in select list.
fromLists [] 4 []
|> isSingle
== True
length : SelectList a -> Basics.Int
Length of SelectList
.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> length
== 6
beforeLength : SelectList a -> Basics.Int
Length of the elements before the selected element
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> beforeLength
== 3
afterLength : SelectList a -> Basics.Int
Length of the elements after the selected element
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> afterLength
== 2
index : SelectList a -> Basics.Int
Index of the selected element.
This is alias of beforeLength
.
index =
beforeLength
reverse : SelectList a -> SelectList a
Reverse a select list. Pivot is selected element.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> reverse
== fromLists [ 6, 5 ] 4 [ 3, 2, 1 ]
attempt : (SelectList a -> Maybe (SelectList a)) -> SelectList a -> SelectList a
Attempt to perform action over selectList and return original SelectList
in cases where this action returns Nothing
.
attempt f selectList =
f selectList
|> Maybe.withDefault selectList
delete : SelectList a -> Maybe (SelectList a)
Delete the selected element, then select an element after the selected.
If a list after selected is empty, then select an element before the selected.
Returns Nothing if SelectList has only single value.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> delete
== Just (fromLists [ 1, 2, 3 ] 5 [ 6 ])
fromLists [ 1, 2, 3 ] 4 []
|> delete
== Just (fromLists [ 1, 2 ] 3 [])
fromLists [] 4 []
|> delete
== Nothing
insertBefore : a -> SelectList a -> SelectList a
Insert new selected element, then move the old before it.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> insertBefore 8
== fromLists [ 1, 2, 3, 4 ] 8 [ 5, 6 ]
insertAfter : a -> SelectList a -> SelectList a
Insert new selected element, then move the old after it.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> insertAfter 8
== fromLists [ 1, 2, 3 ] 8 [ 4, 5, 6 ]
map : (a -> b) -> SelectList a -> SelectList b
Apply a function to every element of a SelectList
.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> map (\num -> num * 2)
== fromLists [ 2, 4, 6 ] 8 [ 10, 12 ]
mapBefore : (a -> a) -> SelectList a -> SelectList a
Apply a function to elements before the selected element.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> mapBefore (\selected -> 2 * selected)
== fromLists [ 2, 4, 6 ] 4 [ 5, 6 ]
mapAfter : (a -> a) -> SelectList a -> SelectList a
Apply a function to elements after the selected element.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> mapAfter (\selected -> 2 * selected)
== fromLists [ 1, 2, 3 ] 4 [ 10, 12 ]
updateSelected : (a -> a) -> SelectList a -> SelectList a
Update the selected element using given function.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> updateSelected (\selected -> 2 * selected)
== fromLists [ 1, 2, 3 ] 8 [ 5, 6 ]
updateBefore : (List a -> List a) -> SelectList a -> SelectList a
Update elements before the selected element using given function.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> updateBefore (\before -> List.map ((*) 2) before)
== fromLists [ 2, 4, 6 ] 4 [ 5, 6 ]
updateAfter : (List a -> List a) -> SelectList a -> SelectList a
Update elements after the selected element using given function.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> updateBefore (\after -> List.map ((*) 2) after)
== fromLists [ 1, 2, 3 ] 4 [ 10, 12 ]
Alias of update function.
replaceX x =
updateX (always x)
replaceSelected : a -> SelectList a -> SelectList a
Replace the selected element with new one.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> replaceSelected 10
== fromLists [ 1, 2, 3 ] 10 [ 5, 6 ]
replaceBefore : List a -> SelectList a -> SelectList a
Replace elements before the selected element with new elements.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> replaceBefore [ 7, 8 ]
== fromLists [ 7, 8 ] 4 [ 5, 6 ]
replaceAfter : List a -> SelectList a -> SelectList a
Replace elements after the selected element with new elements.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> replaceAfter [ 9, 10, 11 ]
== fromLists [ 1, 2, 3 ] 4 [ 9, 10, 11 ]
Position
is used with selectedMap
.
Position
is Selected if the selected element,
BeforeSelected if an element before the selected element,
and AfterSelected if an element after the selected element.
selectedMap : (Position -> SelectList a -> b) -> SelectList a -> List b
Apply a function to every element of a SelectList
.
The transform function receives a Position
and SelectList
which selects a focused element.
Use in view.
view : SelectList String -> Html Msg
view selectList =
ul [] <|
SelectList.selectedMap
(\position item ->
li [ onClick (Set item) ]
[ text <| toString <| SelectList.index item
, toString <| SelectList.selected item
]
)
selectList
Get a focused item and index from select list.
Position
describes whether it is selected, or not.
Compared with List.indexedMap
.
selectedMap : (Position -> SelectList a -> b) -> SelectList a -> List b
indexedMap : (Int -> a -> b) -> List a -> List b
Unlike indexedMap
, we can get full access to all elements in the list.
And set new list to Model
.
If you don't use non-empty list, use selectedMapForList
that receives List
instead of SelectList
.
selectedMapForList : (SelectList a -> b) -> List a -> List b
Apply a function to every element of a List
.
The transform function receives a SelectList
which selects a focused element.
Use in view.
view : SelectList String -> Html Msg
view selectList =
ul [] <|
SelectList.selectedMapForList
(\item ->
li [ onClick (Set <| SelectList.toList <| SelectList.update updateFunction item) ]
[ text <| toString <| SelectList.index item
, toString <| SelectList.selected item
]
)
selectList
Use this instead of indexedMap
.
indexedMap : (Basics.Int -> a -> b) -> SelectList a -> List b
Apply a function to every element of a SelectList
.
The transform function receives an index and an element.
A problem with selectedMap
is to produce many SelectList
s. indexedMap
solves it.
The index is relative. We can create new list with original list and relative index.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> indexedMap (\index elm -> ( index, elm * 2 ))
== [ ( -3, 2 )
, ( -2, 4 )
, ( -1, 6 )
, ( 0, 8 )
, ( 1, 10 )
, ( 2, 12 )
]
indexedMap_ : (Basics.Bool -> Basics.Int -> a -> b) -> SelectList a -> List b
Absolute index version.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> indexedMap_ (\selected index elm -> ( selected, index, 2 * elm ))
== [ ( False, 0, 2 )
, ( False, 1, 4 )
, ( False, 2, 6 )
, ( True, 3, 8 )
, ( False, 4, 10 )
, ( False, 5, 12 )
]
Move selected element.
moveBy : Basics.Int -> SelectList a -> SelectList a
Move a selected element by n steps. Pass an index over the length, then move to head/last.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> moveBy -2
== fromLists [ 1 ] 4 [ 2, 3, 5, 6 ]
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> moveBy 1
== fromLists [ 1, 2, 3, 5 ] 4 [ 6 ]
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> moveBy 3
== fromLists [ 1, 2, 3, 5, 6 ] 4 []
moveWhileLoopBy : Basics.Int -> SelectList a -> SelectList a
Move a selected element by n steps while loop. Pass an index over the length, then loop.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> moveWhileLoopBy 4
== fromLists [ 1 ] 4 [ 2, 3, 5, 6 ]
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> moveWhileLoopBy -4
== fromLists [ 1 2, 3, 5, 6 ] 4 []
moveToHead : SelectList a -> SelectList a
Move a selected element to head.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> moveToHead
== fromLists [] 4 [ 1, 2, 3, 5, 6 ]
moveToLast : SelectList a -> SelectList a
Move a selected element to last.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> moveToLast
== fromLists [ 1, 2, 3, 5, 6 ] 4 []
Select new element, otherwise move focus.
selectBeforeIf : (a -> Basics.Bool) -> SelectList a -> Maybe (SelectList a)
Select the first element, before the old selected, that satisfies a predicate. If none match, return Nothing.
isOdd num =
modBy 2 num /= 0
fromLists [ 1, 2 ] 3 [ 4, 5, 6 ]
|> selectBeforeIf isOdd
== Just (fromLists [ 0 ] 1 [ 2, 3, 4, 5, 6 ])
selectAfterIf : (a -> Basics.Bool) -> SelectList a -> Maybe (SelectList a)
Select the first element, after the old selected, that satisfies a predicate. If none match, return Nothing.
isOdd num =
modBy 2 num /= 0
fromLists [ 1, 2 ] 3 [ 4, 5, 6 ]
|> selectAfterIf isOdd
== Just (fromLists [ 1, 2, 3, 4 ] 5 [ 6 ])
selectBy : Basics.Int -> SelectList a -> Maybe (SelectList a)
Select an element by n steps. Pass an index over the length, then returns Nothing.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selectBy -1
== Just (fromLists [ 1, 2 ] 3 [ 4, 5, 6 ])
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selectBy 2
== Just (fromLists [ 1, 2, 3, 4, 5 ] 6 [])
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selectBy 3
== Nothing
selectWhileLoopBy : Basics.Int -> SelectList a -> SelectList a
Select an element by n steps while loop. Pass an index over the length, then loop.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selectWhileLoopBy 3
== fromLists [] 1 [ 2, 3, 4, 5, 6 ]
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selectWhileLoopBy -5
== fromLists [ 1, 2, 3, 4 ] 5 [ 6 ]
selectHead : SelectList a -> SelectList a
Select a head element.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selectHead
== fromLists [] 1 [ 2, 3, 4, 5, 6 ]
selectLast : SelectList a -> SelectList a
Select a last element.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
|> selectLast
== fromLists [ 1, 2, 3, 4, 5 ] 6 []
selectAll : SelectList a -> List (SelectList a)
List of all SelectList.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
== [ fromLists [] 1 [ 2, 3, 4, 5, 6 ]
, fromLists [ 1 ] 2 [ 3, 4, 5, 6 ]
, fromLists [ 1, 2 ] 3 [ 4, 5, 6 ]
, fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
, fromLists [ 1, 2, 3, 4 ] 5 [ 6 ]
, fromLists [ 1, 2, 3, 4, 5 ] 6 []
]
selectAllBefore : SelectList a -> List (SelectList a)
List of all SelectList before the selected.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
== [ fromLists [] 1 [ 2, 3, 4, 5, 6 ]
, fromLists [ 1 ] 2 [ 3, 4, 5, 6 ]
, fromLists [ 1, 2 ] 3 [ 4, 5, 6 ]
, fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
]
selectAllAfter : SelectList a -> List (SelectList a)
List of all SelectList after the selected.
fromLists [ 1, 2, 3 ] 4 [ 5, 6 ]
== [ fromLists [ 1, 2, 3, 4 ] 5 [ 6 ]
, fromLists [ 1, 2, 3, 4, 5 ] 6 []
]