1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
------------------------------------------------------------------------------
--- This library provides functions to categorize a list of entities
--- into a HTML page with an index access (e.g., "A-Z") to these entities.
------------------------------------------------------------------------------

module HTML.CategorizedList
  ( list2CategorizedHtml, categorizeByItemKey, stringList2ItemList )
 where

import Data.Char
import Data.List

import HTML.Base

--- General categorization of a list of entries.
---
--- The item will occur in every category for which the boolean function
--- categoryFun yields True.
--- @param itemL the list of key-item pairs which are supposed to be
--- categorized with respect to key
--- @param categoryL list of key-category pairs to which the items can be
--- sorted in
--- @param categoryFun uses the keys of the items and the keys of the
--- categories to distribute the items among the categories.
--- @return Html containing inner links between the categories
list2CategorizedHtml ::
  (HTML h, Show b) => [(a,[h])] -> [(b,String)] -> (a -> b -> Bool) -> [h]
list2CategorizedHtml itemL categoryL categoryFun =
   categories2LinkList categoryL :
   map (\ (categoryKey,categoryString) ->
          anchor (string2urlencoded (show categoryKey))
                 (h2 [htxt categoryString] :
                  concatMap (\ (_,item)->item++[breakline])
                            (filter (\ (itemKey,_) ->
                                            categoryFun itemKey categoryKey)
                                     itemL)
                     ++ [categories2LinkList categoryL])
         )
        categoryL

-- the navigation list
categories2LinkList :: (HTML h, Show a) => [(a,String)] -> h
categories2LinkList categoryL =
  par
  [center
    (concatMap (\ (categoryKey,categoryString) ->
                     [href ('#':(string2urlencoded (show categoryKey)))
                           [htxt categoryString], nbsp])
               categoryL)]

--- Categorize a list of entries with respect to the inial keys.
---
--- The categories are named as all initial characters of the keys of the items.
--- @param itemL  the list of key-item pairs which are supposed to be
--- categorized with respect to key
--- @return Html containing inner links between the categories
categorizeByItemKey :: HTML h => [(String,[h])] -> [h]
categorizeByItemKey itemL =
   list2CategorizedHtml
       itemL
       (map (\c -> (toUpper c,[toUpper c])) (listHeads (map fst itemL)))
       categorizeStringHead

--- Convert a string list into an key-item list
--- The strings are used as keys and for the simple text layout.
stringList2ItemList :: HTML h => [String] -> [(String,[h])]
stringList2ItemList = map (\str -> (str,[htxt str]))

-- yields every listHead only once
listHeads :: [String] -> [Char]
listHeads =
  nubBy isUpperEqual . foldr (\xs ys -> if xs==[] then ys else head xs:ys) []

-- categoryFun for categorizeByItemKey
categorizeStringHead :: String -> Char -> Bool
categorizeStringHead [] _ = False
categorizeStringHead (c:_) c' = isUpperEqual c c'

isUpperEqual :: Char -> Char -> Bool
isUpperEqual c c' = toUpper c == toUpper c'


-- just for testing ----------------------------------------

main :: IO HtmlPage
main = return $ page "CatTest"
                     (categorizeByItemKey (stringList2ItemList testList))

testList :: [String]
testList = ["bbcd",
            "acde",
            "ab",
            "cde",
            "b",
            "xt",
            "gbbcd",
            "uacde",
            "Oab",
            "Qcde",
            "Tb",
            "mxt",
            "mxtr"]

-- To test, export `main` and run:
-- > cypm exec curry2cgi -o ~/public_html/cgi-bin/cat.cgi HTML.CategorizedList