more flexible js loading
* write your own async jsLoader widget. * Suport loading from the bottom of body tag. Bottom of the page is actually the best default until you profile your application.
This commit is contained in:
parent
a58f859d41
commit
651a1f8abd
@ -27,6 +27,9 @@ module Yesod.Core
|
|||||||
, logWarn
|
, logWarn
|
||||||
, logError
|
, logError
|
||||||
, logOther
|
, logOther
|
||||||
|
-- * JS loaders
|
||||||
|
, loadJsYepnope
|
||||||
|
, ScriptLoadPosition (..)
|
||||||
-- * Misc
|
-- * Misc
|
||||||
, yesodVersion
|
, yesodVersion
|
||||||
, yesodRender
|
, yesodRender
|
||||||
|
|||||||
@ -25,6 +25,9 @@ module Yesod.Internal.Core
|
|||||||
, formatLogMessage
|
, formatLogMessage
|
||||||
, fileLocationToString
|
, fileLocationToString
|
||||||
, messageLoggerHandler
|
, messageLoggerHandler
|
||||||
|
-- * jsLoader
|
||||||
|
, ScriptLoadPosition (..)
|
||||||
|
, loadJsYepnope
|
||||||
-- * Misc
|
-- * Misc
|
||||||
, yesodVersion
|
, yesodVersion
|
||||||
, yesodRender
|
, yesodRender
|
||||||
@ -313,11 +316,20 @@ class RenderRoute a => Yesod a where
|
|||||||
gzipSettings :: a -> GzipSettings
|
gzipSettings :: a -> GzipSettings
|
||||||
gzipSettings _ = def
|
gzipSettings _ = def
|
||||||
|
|
||||||
-- | Location of yepnope.js, if any. If one is provided, then all
|
-- | Deprecated. Use 'jsloader'. To use yepnope: jsLoader = BottomOfHeadAsync (loadJsYepnope eyn)
|
||||||
|
-- Location of yepnope.js, if any. If one is provided, then all
|
||||||
-- Javascript files will be loaded asynchronously.
|
-- Javascript files will be loaded asynchronously.
|
||||||
yepnopeJs :: a -> Maybe (Either Text (Route a))
|
yepnopeJs :: a -> Maybe (Either Text (Route a))
|
||||||
yepnopeJs _ = Nothing
|
yepnopeJs _ = Nothing
|
||||||
|
|
||||||
|
-- | Where to Load sripts from. We recommend changing this to 'BottomOfBody'
|
||||||
|
-- Alternatively use the built in async yepnope loader: BottomOfHeadAsync (loadJsYepnope eyn)
|
||||||
|
-- Or write your own async js loader: see 'loadJsYepnope'
|
||||||
|
jsLoader :: a -> ScriptLoadPosition a
|
||||||
|
jsLoader y = case yepnopeJs y of
|
||||||
|
Nothing -> BottomOfHeadBlocking
|
||||||
|
Just eyn -> BottomOfHeadAsync (loadJsYepnope eyn)
|
||||||
|
|
||||||
messageLoggerHandler :: Yesod m
|
messageLoggerHandler :: Yesod m
|
||||||
=> Loc -> LogLevel -> Text -> GHandler s m ()
|
=> Loc -> LogLevel -> Text -> GHandler s m ()
|
||||||
messageLoggerHandler loc level msg = do
|
messageLoggerHandler loc level msg = do
|
||||||
@ -573,7 +585,16 @@ widgetToPageContent w = do
|
|||||||
|
|
||||||
-- modernizr should be at the end of the <head> http://www.modernizr.com/docs/#installing
|
-- modernizr should be at the end of the <head> http://www.modernizr.com/docs/#installing
|
||||||
-- the asynchronous loader means your page doesn't have to wait for all the js to load
|
-- the asynchronous loader means your page doesn't have to wait for all the js to load
|
||||||
let (mcomplete, ynscripts) = ynHelper render scripts jscript jsLoc
|
let (mcomplete, asyncScripts) = asyncHelper render scripts jscript jsLoc
|
||||||
|
regularScriptLoad = [HAMLET|
|
||||||
|
$forall s <- scripts
|
||||||
|
^{mkScriptTag s}
|
||||||
|
$maybe j <- jscript
|
||||||
|
$maybe s <- jsLoc
|
||||||
|
<script src="#{s}">
|
||||||
|
$nothing
|
||||||
|
<script>^{jelper j}
|
||||||
|
|]
|
||||||
headAll = [HAMLET|
|
headAll = [HAMLET|
|
||||||
\^{head'}
|
\^{head'}
|
||||||
$forall s <- stylesheets
|
$forall s <- stylesheets
|
||||||
@ -589,31 +610,21 @@ $forall s <- css
|
|||||||
<style media=#{media}>#{content}
|
<style media=#{media}>#{content}
|
||||||
$nothing
|
$nothing
|
||||||
<style>#{content}
|
<style>#{content}
|
||||||
$maybe eyn <- yepnopeJs master
|
$case jsLoader master
|
||||||
$maybe yn <- left eyn
|
$of BottomOfHeadAsync asyncJsLoader
|
||||||
<script src=#{yn}>
|
^{asyncJsLoader asyncScripts mcomplete}
|
||||||
$maybe yn <- right eyn
|
$of BottomOfHeadBlocking
|
||||||
<script src=@{yn}>
|
^{regularScriptLoad}
|
||||||
$maybe complete <- mcomplete
|
$of BottomOfBody
|
||||||
<script>yepnope({load:#{ynscripts},complete:function(){^{complete}}})
|
|
||||||
$nothing
|
|
||||||
<script>yepnope({load:#{ynscripts}})
|
|
||||||
$nothing
|
|
||||||
$forall s <- scripts
|
|
||||||
^{mkScriptTag s}
|
|
||||||
$maybe j <- jscript
|
|
||||||
$maybe s <- jsLoc
|
|
||||||
<script src="#{s}">
|
|
||||||
$nothing
|
|
||||||
<script>^{jelper j}
|
|
||||||
|]
|
|]
|
||||||
return $ PageContent title headAll body
|
let bodyScript = [HAMLET|
|
||||||
|
^{body}
|
||||||
|
^{regularScriptLoad}
|
||||||
|
|]
|
||||||
|
return $ PageContent title headAll (case jsLoader master of
|
||||||
|
BottomOfBody -> bodyScript
|
||||||
|
_ -> body)
|
||||||
where
|
where
|
||||||
left (Left x) = Just x
|
|
||||||
left _ = Nothing
|
|
||||||
right (Right x) = Just x
|
|
||||||
right _ = Nothing
|
|
||||||
|
|
||||||
renderLoc' render' (Local url) = render' url []
|
renderLoc' render' (Local url) = render' url []
|
||||||
renderLoc' _ (Remote s) = s
|
renderLoc' _ (Remote s) = s
|
||||||
|
|
||||||
@ -627,13 +638,44 @@ $nothing
|
|||||||
: attrs
|
: attrs
|
||||||
)
|
)
|
||||||
|
|
||||||
ynHelper :: (url -> [x] -> Text)
|
data Yesod master => ScriptLoadPosition master = BottomOfBody | BottomOfHeadBlocking | BottomOfHeadAsync (
|
||||||
|
[Text] -- ^ urls to load asynchronously
|
||||||
|
-> Maybe (HtmlUrl (Route master)) -- ^ widget of js to run on async completion
|
||||||
|
-> (HtmlUrl (Route master)) -- ^ widget to insert at the bottom of <head>
|
||||||
|
)
|
||||||
|
|
||||||
|
left :: Either a b -> Maybe a
|
||||||
|
left (Left x) = Just x
|
||||||
|
left _ = Nothing
|
||||||
|
|
||||||
|
right :: Either a b -> Maybe b
|
||||||
|
right (Right x) = Just x
|
||||||
|
right _ = Nothing
|
||||||
|
|
||||||
|
jsonArray :: [Text] -> Html
|
||||||
|
jsonArray = unsafeLazyByteString . encode . Array . Vector.fromList . map String
|
||||||
|
|
||||||
|
-- | For use with setting 'jsLoader' to 'BottomOfHeadAsync'
|
||||||
|
loadJsYepnope :: Yesod master => Either Text (Route master) -> [Text] -> Maybe (HtmlUrl (Route master)) -> (HtmlUrl (Route master))
|
||||||
|
loadJsYepnope eyn scripts mcomplete =
|
||||||
|
[HAMLET|
|
||||||
|
$maybe yn <- left eyn
|
||||||
|
<script src=#{yn}>
|
||||||
|
$maybe yn <- right eyn
|
||||||
|
<script src=@{yn}>
|
||||||
|
$maybe complete <- mcomplete
|
||||||
|
<script>yepnope({load:#{jsonArray scripts},complete:function(){^{complete}}});
|
||||||
|
$nothing
|
||||||
|
<script>yepnope({load:#{jsonArray scripts}});
|
||||||
|
|]
|
||||||
|
|
||||||
|
asyncHelper :: (url -> [x] -> Text)
|
||||||
-> [Script (url)]
|
-> [Script (url)]
|
||||||
-> Maybe (JavascriptUrl (url))
|
-> Maybe (JavascriptUrl (url))
|
||||||
-> Maybe Text
|
-> Maybe Text
|
||||||
-> (Maybe (HtmlUrl (url)), Html)
|
-> (Maybe (HtmlUrl url), [Text])
|
||||||
ynHelper render scripts jscript jsLoc =
|
asyncHelper render scripts jscript jsLoc =
|
||||||
(mcomplete, unsafeLazyByteString $ encode $ Array $ Vector.fromList $ map String scripts'')
|
(mcomplete, scripts'')
|
||||||
where
|
where
|
||||||
scripts' = map goScript scripts
|
scripts' = map goScript scripts
|
||||||
scripts'' =
|
scripts'' =
|
||||||
|
|||||||
@ -11,7 +11,7 @@ module Yesod.Form.Nic
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
import Yesod.Handler
|
import Yesod.Handler
|
||||||
import Yesod.Core (Route, yepnopeJs, Yesod)
|
import Yesod.Core (Route, ScriptLoadPosition(..), jsLoader, Yesod)
|
||||||
import Yesod.Form
|
import Yesod.Form
|
||||||
import Yesod.Widget
|
import Yesod.Widget
|
||||||
import Text.HTML.SanitizeXSS (sanitizeBalance)
|
import Text.HTML.SanitizeXSS (sanitizeBalance)
|
||||||
@ -43,8 +43,8 @@ nicHtmlField = Field
|
|||||||
addScript' urlNicEdit
|
addScript' urlNicEdit
|
||||||
master <- lift getYesod
|
master <- lift getYesod
|
||||||
addJulius $
|
addJulius $
|
||||||
case yepnopeJs master of
|
case jsLoader master of
|
||||||
Nothing ->
|
BottomOfHeadBlocking ->
|
||||||
#if __GLASGOW_HASKELL__ >= 700
|
#if __GLASGOW_HASKELL__ >= 700
|
||||||
[julius|
|
[julius|
|
||||||
#else
|
#else
|
||||||
@ -52,7 +52,7 @@ nicHtmlField = Field
|
|||||||
#endif
|
#endif
|
||||||
bkLib.onDomLoaded(function(){new nicEditor({fullPanel:true}).panelInstance("#{theId}")});
|
bkLib.onDomLoaded(function(){new nicEditor({fullPanel:true}).panelInstance("#{theId}")});
|
||||||
|]
|
|]
|
||||||
Just _ ->
|
_ ->
|
||||||
#if __GLASGOW_HASKELL__ >= 700
|
#if __GLASGOW_HASKELL__ >= 700
|
||||||
[julius|
|
[julius|
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -121,8 +121,8 @@ instance Yesod ~sitearg~ where
|
|||||||
-- users receiving stale content.
|
-- users receiving stale content.
|
||||||
addStaticContent = addStaticContentExternal minifym base64md5 Settings.staticDir (StaticR . flip StaticRoute [])
|
addStaticContent = addStaticContentExternal minifym base64md5 Settings.staticDir (StaticR . flip StaticRoute [])
|
||||||
|
|
||||||
-- Enable Javascript async loading
|
-- Place Javascript at bottom of the body tag so the rest of the page loads first
|
||||||
yepnopeJs _ = Just $ Right $ StaticR js_modernizr_js
|
jsLoader _ = BottomOfBody
|
||||||
|
|
||||||
-- How to run database actions.
|
-- How to run database actions.
|
||||||
instance YesodPersist ~sitearg~ where
|
instance YesodPersist ~sitearg~ where
|
||||||
|
|||||||
@ -95,5 +95,5 @@ instance Yesod ~sitearg~ where
|
|||||||
-- users receiving stale content.
|
-- users receiving stale content.
|
||||||
addStaticContent = addStaticContentExternal (const $ Left ()) base64md5 Settings.staticDir (StaticR . flip StaticRoute [])
|
addStaticContent = addStaticContentExternal (const $ Left ()) base64md5 Settings.staticDir (StaticR . flip StaticRoute [])
|
||||||
|
|
||||||
-- Enable Javascript async loading
|
-- Place Javascript at bottom of the body tag so the rest of the page loads first
|
||||||
yepnopeJs _ = Just $ Right $ StaticR js_modernizr_js
|
jsLoader _ = BottomOfBody
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user