Jquery.hs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. {-# LANGUAGE QuasiQuotes #-}
  2. {-# LANGUAGE TypeFamilies #-}
  3. {-# LANGUAGE FlexibleContexts #-}
  4. {-# LANGUAGE OverloadedStrings #-}
  5. -- | Some fields spiced up with jQuery UI.
  6. module Yesod.Form.Jquery
  7. ( YesodJquery (..)
  8. , jqueryDayField
  9. , jqueryDatePickerDayField
  10. , jqueryAutocompleteField
  11. , jqueryAutocompleteField'
  12. , googleHostedJqueryUiCss
  13. , JqueryDaySettings (..)
  14. , Default (..)
  15. ) where
  16. import Yesod.Core
  17. import Yesod.Form
  18. import Data.Time (Day)
  19. import Data.Default
  20. import Text.Hamlet (shamlet)
  21. import Text.Julius (julius, rawJS)
  22. import Data.Text (Text, pack, unpack)
  23. import Data.Monoid (mconcat)
  24. -- | Gets the Google hosted jQuery UI 1.8 CSS file with the given theme.
  25. googleHostedJqueryUiCss :: Text -> Text
  26. googleHostedJqueryUiCss theme = mconcat
  27. [ "//ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/"
  28. , theme
  29. , "/jquery-ui.css"
  30. ]
  31. class YesodJquery a where
  32. -- | The jQuery Javascript file. Note that in upgrades to this library, the
  33. -- version of jQuery referenced, or where it is downloaded from, may be
  34. -- changed without warning. If you are relying on a specific version of
  35. -- jQuery, you should give an explicit URL instead of relying on the
  36. -- default value.
  37. --
  38. -- Currently, the default value is jQuery 1.7 from Google\'s CDN.
  39. urlJqueryJs :: a -> Either (Route a) Text
  40. urlJqueryJs _ = Right "//ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"
  41. -- | The jQuery UI 1.8 Javascript file.
  42. urlJqueryUiJs :: a -> Either (Route a) Text
  43. urlJqueryUiJs _ = Right "//ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"
  44. -- | The jQuery UI 1.8 CSS file; defaults to cupertino theme.
  45. urlJqueryUiCss :: a -> Either (Route a) Text
  46. urlJqueryUiCss _ = Right $ googleHostedJqueryUiCss "cupertino"
  47. -- | jQuery UI time picker add-on.
  48. urlJqueryUiDateTimePicker :: a -> Either (Route a) Text
  49. urlJqueryUiDateTimePicker _ = Right "http://github.com/gregwebs/jquery.ui.datetimepicker/raw/master/jquery.ui.datetimepicker.js"
  50. jqueryDayField :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Field (HandlerT site IO) Day
  51. jqueryDayField = flip jqueryDayField' "date"
  52. -- | Use jQuery's datepicker as the underlying implementation.
  53. --
  54. -- Since 1.4.3
  55. jqueryDatePickerDayField :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Field (HandlerT site IO) Day
  56. jqueryDatePickerDayField = flip jqueryDayField' "text"
  57. jqueryDayField' :: (RenderMessage site FormMessage, YesodJquery site) => JqueryDaySettings -> Text -> Field (HandlerT site IO) Day
  58. jqueryDayField' jds inputType = Field
  59. { fieldParse = parseHelper $ maybe
  60. (Left MsgInvalidDay)
  61. Right
  62. . readMay
  63. . unpack
  64. , fieldView = \theId name attrs val isReq -> do
  65. toWidget [shamlet|
  66. $newline never
  67. <input id="#{theId}" name="#{name}" *{attrs} type="#{inputType}" :isReq:required="" value="#{showVal val}">
  68. |]
  69. addScript' urlJqueryJs
  70. addScript' urlJqueryUiJs
  71. addStylesheet' urlJqueryUiCss
  72. toWidget [julius|
  73. $(function(){
  74. var i = document.getElementById("#{rawJS theId}");
  75. if (i.type != "date") {
  76. $(i).datepicker({
  77. dateFormat:'yy-mm-dd',
  78. changeMonth:#{jsBool $ jdsChangeMonth jds},
  79. changeYear:#{jsBool $ jdsChangeYear jds},
  80. numberOfMonths:#{rawJS $ mos $ jdsNumberOfMonths jds},
  81. yearRange:#{toJSON $ jdsYearRange jds}
  82. });
  83. }
  84. });
  85. |]
  86. , fieldEnctype = UrlEncoded
  87. }
  88. where
  89. showVal = either id (pack . show)
  90. jsBool True = toJSON True
  91. jsBool False = toJSON False
  92. mos (Left i) = show i
  93. mos (Right (x, y)) = concat
  94. [ "["
  95. , show x
  96. , ","
  97. , show y
  98. , "]"
  99. ]
  100. jqueryAutocompleteField :: (RenderMessage site FormMessage, YesodJquery site)
  101. => Route site -> Field (HandlerT site IO) Text
  102. jqueryAutocompleteField = jqueryAutocompleteField' 2
  103. jqueryAutocompleteField' :: (RenderMessage site FormMessage, YesodJquery site)
  104. => Int -- ^ autocomplete minimum length
  105. -> Route site
  106. -> Field (HandlerT site IO) Text
  107. jqueryAutocompleteField' minLen src = Field
  108. { fieldParse = parseHelper $ Right
  109. , fieldView = \theId name attrs val isReq -> do
  110. toWidget [shamlet|
  111. $newline never
  112. <input id="#{theId}" name="#{name}" *{attrs} type="text" :isReq:required="" value="#{either id id val}" .autocomplete>
  113. |]
  114. addScript' urlJqueryJs
  115. addScript' urlJqueryUiJs
  116. addStylesheet' urlJqueryUiCss
  117. toWidget [julius|
  118. $(function(){$("##{rawJS theId}").autocomplete({source:"@{src}",minLength:#{toJSON minLen}})});
  119. |]
  120. , fieldEnctype = UrlEncoded
  121. }
  122. addScript' :: (HandlerSite m ~ site, MonadWidget m) => (site -> Either (Route site) Text) -> m ()
  123. addScript' f = do
  124. y <- getYesod
  125. addScriptEither $ f y
  126. addStylesheet' :: (MonadWidget m, HandlerSite m ~ site)
  127. => (site -> Either (Route site) Text)
  128. -> m ()
  129. addStylesheet' f = do
  130. y <- getYesod
  131. addStylesheetEither $ f y
  132. readMay :: Read a => String -> Maybe a
  133. readMay s = case reads s of
  134. (x, _):_ -> Just x
  135. [] -> Nothing
  136. data JqueryDaySettings = JqueryDaySettings
  137. { jdsChangeMonth :: Bool
  138. , jdsChangeYear :: Bool
  139. , jdsYearRange :: String
  140. , jdsNumberOfMonths :: Either Int (Int, Int)
  141. }
  142. instance Default JqueryDaySettings where
  143. def = JqueryDaySettings
  144. { jdsChangeMonth = False
  145. , jdsChangeYear = False
  146. , jdsYearRange = "c-10:c+10"
  147. , jdsNumberOfMonths = Left 1
  148. }