merge master branch
This commit is contained in:
commit
00b9acd98d
16
README.md
16
README.md
@ -95,9 +95,12 @@ virthualenv --name=yesod
|
||||
#### individual cabal packages
|
||||
|
||||
~~~ { .bash }
|
||||
# install and test all packages
|
||||
# install and test all packages in a repo
|
||||
./scripts/install
|
||||
|
||||
# If things seem weird, you may need to do a clean.
|
||||
./scripts/install --clean
|
||||
|
||||
# move to the individual package you are working on
|
||||
cd shakespeare-text
|
||||
|
||||
@ -109,17 +112,12 @@ cabal test
|
||||
|
||||
#### cabal-dev
|
||||
|
||||
cabal-dev works very well if you are working on a single package, but it can be very cumbersome to work on multiple packages at once.
|
||||
cabal-dev works very well if you are working on a single package.
|
||||
For working on multiple packages at once (installing Yesod), you need to use the shared sandbox feature.
|
||||
|
||||
### Use your development version of Yesod in your application
|
||||
|
||||
Note that we have recommended to you to install Yesod into a sandboxed virthualenv environment.
|
||||
This is great for development, but when you want to use these development versions in your application that means they are not available through your user/global cabal database for your application.
|
||||
You should just continue to use your yesod virthualenv shell for your application.
|
||||
|
||||
You can also use `cabal-dev install` to retrieve these packages.
|
||||
cd to your application directory, and the reference the source list.
|
||||
|
||||
~~~ { .bash }
|
||||
cabal-dev install /path/to/yesodweb/yesod/*(/)
|
||||
~~~
|
||||
You can also use the same`cabal-dev shared sandbox.
|
||||
|
||||
2
scripts
2
scripts
@ -1 +1 @@
|
||||
Subproject commit d4cb555ca5fd6bc67f7da484a63d1fcdb149eac9
|
||||
Subproject commit 6a95e0a8dbc1b3d26d58c1eaadf24d1bdaa48c8b
|
||||
21
sources.txt
21
sources.txt
@ -1,10 +1,11 @@
|
||||
yesod-core
|
||||
yesod-json
|
||||
yesod-static
|
||||
yesod-persistent
|
||||
yesod-newsfeed
|
||||
yesod-form
|
||||
yesod-auth
|
||||
yesod-sitemap
|
||||
yesod-default
|
||||
yesod
|
||||
./yesod-routes
|
||||
./yesod-core
|
||||
./yesod-json
|
||||
./yesod-static
|
||||
./yesod-persistent
|
||||
./yesod-newsfeed
|
||||
./yesod-form
|
||||
./yesod-auth
|
||||
./yesod-sitemap
|
||||
./yesod-default
|
||||
./yesod
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
The following license covers this documentation, and the source code, except
|
||||
where otherwise indicated.
|
||||
|
||||
Copyright 2010, Michael Snoyman. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env runhaskell
|
||||
|
||||
> module Main where
|
||||
> import Distribution.Simple
|
||||
> import System.Cmd (system)
|
||||
|
||||
> main :: IO ()
|
||||
> main = defaultMain
|
||||
@ -1,123 +0,0 @@
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
-- | In-built kerberos authentication for Yesod.
|
||||
--
|
||||
-- Please note that all configuration should have been done
|
||||
-- manually on the machine prior to running the code.
|
||||
--
|
||||
-- On linux machines the configuration might be in /etc/krb5.conf.
|
||||
-- It's worth checking if the Kerberos service provider (e.g. your university)
|
||||
-- already provide a complete configuration file.
|
||||
--
|
||||
-- Be certain that you can manually login from a shell by typing
|
||||
--
|
||||
-- > kinit username
|
||||
--
|
||||
-- If you fill in your password and the program returns no error code,
|
||||
-- then your kerberos configuration is setup properly.
|
||||
-- Only then can this module be of any use.
|
||||
module Yesod.Auth.Kerberos
|
||||
( authKerberos,
|
||||
genericAuthKerberos,
|
||||
KerberosConfig(..),
|
||||
defaultKerberosConfig
|
||||
) where
|
||||
|
||||
#include "qq.h"
|
||||
|
||||
import Yesod.Auth
|
||||
import Yesod.Auth.Message
|
||||
import Web.Authenticate.Kerberos
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Text.Hamlet
|
||||
import Yesod.Handler
|
||||
import Yesod.Widget
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import Yesod.Form
|
||||
import Control.Applicative ((<$>), (<*>))
|
||||
|
||||
data KerberosConfig = KerberosConfig {
|
||||
-- | When a user gives username x, f(x) will be passed to Kerberos
|
||||
usernameModifier :: Text -> Text
|
||||
-- | When a user gives username x, f(x) will be passed to Yesod
|
||||
, identifierModifier :: Text -> Text
|
||||
}
|
||||
|
||||
-- | A configuration where the username the user provides is the one passed
|
||||
-- to both kerberos and yesod
|
||||
defaultKerberosConfig :: KerberosConfig
|
||||
defaultKerberosConfig = KerberosConfig id id
|
||||
|
||||
-- | A configurable version of 'authKerberos'
|
||||
genericAuthKerberos :: YesodAuth m => KerberosConfig -> AuthPlugin m
|
||||
genericAuthKerberos config = AuthPlugin "kerberos" dispatch $ \tm -> addHamlet
|
||||
[QQ(hamlet)|
|
||||
<div id="header">
|
||||
<h1>Login
|
||||
|
||||
<div id="login">
|
||||
<form method="post" action="@{tm login}">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Username:
|
||||
<td>
|
||||
<input id="x" name="username" autofocus="" required>
|
||||
<tr>
|
||||
<th>Password:
|
||||
<td>
|
||||
<input type="password" name="password" required>
|
||||
<tr>
|
||||
<td>
|
||||
<td>
|
||||
<input type="submit" value="Login">
|
||||
|
||||
<script>
|
||||
if (!("autofocus" in document.createElement("input"))) {
|
||||
document.getElementById("x").focus();
|
||||
}
|
||||
|]
|
||||
where
|
||||
dispatch "POST" ["login"] = postLoginR config >>= sendResponse
|
||||
dispatch _ _ = notFound
|
||||
|
||||
login :: AuthRoute
|
||||
login = PluginR "kerberos" ["login"]
|
||||
|
||||
-- | Kerberos with 'defaultKerberosConfig'
|
||||
authKerberos :: YesodAuth m => AuthPlugin m
|
||||
authKerberos = genericAuthKerberos defaultKerberosConfig
|
||||
|
||||
-- | Handle the login form
|
||||
postLoginR :: (YesodAuth y) => KerberosConfig -> GHandler Auth y ()
|
||||
postLoginR config = do
|
||||
(mu,mp) <- runInputPost $ (,)
|
||||
<$> iopt textField "username"
|
||||
<*> iopt textField "password"
|
||||
|
||||
let errorMessage (message :: Text) = do
|
||||
setMessage [QQ(shamlet)|Error: #{message}|]
|
||||
toMaster <- getRouteToMaster
|
||||
redirect $ toMaster LoginR
|
||||
|
||||
case (mu,mp) of
|
||||
(Nothing, _ ) -> do
|
||||
mr <- getMessageRender
|
||||
errorMessage $ mr PleaseProvideUsername
|
||||
(_ , Nothing) -> do
|
||||
mr <- getMessageRender
|
||||
errorMessage $ mr PleaseProvidePassword
|
||||
(Just u , Just p ) -> do
|
||||
result <- liftIO $ loginKerberos (usernameModifier config u) p
|
||||
case result of
|
||||
Ok -> do
|
||||
let creds = Creds
|
||||
{ credsIdent = identifierModifier config u
|
||||
, credsPlugin = "Kerberos"
|
||||
, credsExtra = []
|
||||
}
|
||||
setCreds True creds
|
||||
kerberosError -> errorMessage (T.pack $ show kerberosError)
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
|
||||
-- CPP macro which choses which quasyquotes syntax to use depending
|
||||
-- on GHC version.
|
||||
--
|
||||
-- QQ stands for quasyquote.
|
||||
#if GHC7
|
||||
# define QQ(x) x
|
||||
#else
|
||||
# define QQ(x) $x
|
||||
#endif
|
||||
@ -1,39 +0,0 @@
|
||||
name: yesod-auth-kerberos
|
||||
version: 0.8.0
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
author: Arash Rouhani
|
||||
maintainer: Arash Rouhani
|
||||
synopsis: Kerberos Authentication for Yesod.
|
||||
category: Web, Yesod
|
||||
stability: Stable
|
||||
cabal-version: >= 1.6.0
|
||||
build-type: Simple
|
||||
homepage: http://www.yesodweb.com/
|
||||
extra-source-files: include/qq.h
|
||||
description: Kerberos Authentication for Yesod.
|
||||
|
||||
flag ghc7
|
||||
|
||||
library
|
||||
if flag(ghc7)
|
||||
build-depends: base >= 4.3 && < 5
|
||||
cpp-options: -DGHC7
|
||||
else
|
||||
build-depends: base >= 4 && < 4.3
|
||||
build-depends: authenticate-kerberos >= 1.0 && < 1.1
|
||||
, bytestring >= 0.9.1.4 && < 0.10
|
||||
, yesod-core >= 0.10 && < 0.11
|
||||
, yesod-auth >= 0.8 && < 0.9
|
||||
, text >= 0.7 && < 0.12
|
||||
, hamlet >= 0.10 && < 0.11
|
||||
, yesod-form >= 0.4 && < 0.5
|
||||
, transformers >= 0.2.2 && < 0.3
|
||||
|
||||
exposed-modules: Yesod.Auth.Kerberos
|
||||
ghc-options: -Wall
|
||||
include-dirs: include
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/yesodweb/yesod
|
||||
@ -5,6 +5,7 @@ module Yesod.Auth.OAuth
|
||||
, oauthUrl
|
||||
, authTwitter
|
||||
, twitterUrl
|
||||
, module Web.Authenticate.OAuth
|
||||
) where
|
||||
|
||||
#include "qq.h"
|
||||
@ -16,71 +17,86 @@ import Yesod.Widget
|
||||
import Text.Hamlet (shamlet)
|
||||
import Web.Authenticate.OAuth
|
||||
import Data.Maybe
|
||||
import Data.String
|
||||
import Data.ByteString.Char8 (pack)
|
||||
import Control.Arrow ((***))
|
||||
import Data.Text (Text, unpack)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Text.Encoding (encodeUtf8, decodeUtf8With)
|
||||
import Data.Text.Encoding.Error (lenientDecode)
|
||||
import Data.ByteString (ByteString)
|
||||
import Control.Applicative ((<$>), (<*>))
|
||||
import Data.Conduit
|
||||
|
||||
oauthUrl :: Text -> AuthRoute
|
||||
oauthUrl name = PluginR name ["forward"]
|
||||
|
||||
authOAuth :: YesodAuth m =>
|
||||
Text -- ^ Service Name
|
||||
-> String -- ^ OAuth Parameter Name to use for identify
|
||||
-> String -- ^ Request URL
|
||||
-> String -- ^ Access Token URL
|
||||
-> String -- ^ Authorize URL
|
||||
-> String -- ^ Consumer Key
|
||||
-> String -- ^ Consumer Secret
|
||||
authOAuth :: YesodAuth m
|
||||
=> OAuth -- ^ 'OAuth' data-type for signing.
|
||||
-> (Credential -> IO (Creds m)) -- ^ How to extract ident.
|
||||
-> AuthPlugin m
|
||||
authOAuth name ident reqUrl accUrl authUrl key sec = AuthPlugin name dispatch login
|
||||
authOAuth oauth mkCreds = AuthPlugin name dispatch login
|
||||
where
|
||||
name = T.pack $ oauthServerName oauth
|
||||
url = PluginR name []
|
||||
oauth = OAuth { oauthServerName = unpack name, oauthRequestUri = reqUrl
|
||||
, oauthAccessTokenUri = accUrl, oauthAuthorizeUri = authUrl
|
||||
, oauthSignatureMethod = HMACSHA1
|
||||
, oauthConsumerKey = fromString key, oauthConsumerSecret = fromString sec
|
||||
, oauthCallback = Nothing
|
||||
, oauthRealm = Nothing
|
||||
}
|
||||
lookupTokenSecret = bsToText . fromMaybe "" . lookup "oauth_token_secret" . unCredential
|
||||
oauthSessionName = "__oauth_token_secret"
|
||||
dispatch "GET" ["forward"] = do
|
||||
render <- getUrlRender
|
||||
tm <- getRouteToMaster
|
||||
let oauth' = oauth { oauthCallback = Just $ encodeUtf8 $ render $ tm url }
|
||||
master <- getYesod
|
||||
tok <- lift $ getTemporaryCredential oauth' (authHttpManager master)
|
||||
setSession oauthSessionName $ lookupTokenSecret tok
|
||||
redirect $ authorizeUrl oauth' tok
|
||||
dispatch "GET" [] = do
|
||||
(verifier, oaTok) <- runInputGet $ (,)
|
||||
<$> ireq textField "oauth_verifier"
|
||||
<*> ireq textField "oauth_token"
|
||||
let reqTok = Credential [ ("oauth_verifier", encodeUtf8 verifier), ("oauth_token", encodeUtf8 oaTok)
|
||||
reqTok <-
|
||||
if oauthVersion oauth == OAuth10
|
||||
then do
|
||||
oaTok <- runInputGet $ ireq textField "oauth_token"
|
||||
tokSec <- fromJust <$> lookupSession oauthSessionName
|
||||
deleteSession oauthSessionName
|
||||
return $ Credential [ ("oauth_token", encodeUtf8 oaTok)
|
||||
, ("oauth_token_secret", encodeUtf8 tokSec)
|
||||
]
|
||||
master <- getYesod
|
||||
accTok <- lift $ getAccessToken oauth reqTok (authHttpManager master)
|
||||
let crId = decodeUtf8With lenientDecode $ fromJust $ lookup (pack ident) $ unCredential accTok
|
||||
creds = Creds name crId $ map (bsToText *** bsToText ) $ unCredential accTok
|
||||
setCreds True creds
|
||||
else do
|
||||
(verifier, oaTok) <-
|
||||
runInputGet $ (,) <$> ireq textField "oauth_verifier"
|
||||
<*> ireq textField "oauth_token"
|
||||
tokSec <- fromJust <$> lookupSession oauthSessionName
|
||||
deleteSession oauthSessionName
|
||||
return $ Credential [ ("oauth_verifier", encodeUtf8 verifier)
|
||||
, ("oauth_token", encodeUtf8 oaTok)
|
||||
, ("oauth_token_secret", encodeUtf8 tokSec)
|
||||
]
|
||||
master <- getYesod
|
||||
accTok <- lift $ getAccessToken oauth reqTok (authHttpManager master)
|
||||
creds <- resourceLiftBase $ mkCreds accTok
|
||||
setCreds True creds
|
||||
dispatch _ _ = notFound
|
||||
login tm = do
|
||||
render <- lift getUrlRender
|
||||
let oaUrl = render $ tm $ oauthUrl name
|
||||
addHtml
|
||||
[QQ(shamlet)| <a href=#{oaUrl}>Login with #{name} |]
|
||||
[QQ(shamlet)| <a href=#{oaUrl}>Login via #{name} |]
|
||||
|
||||
authTwitter :: YesodAuth m =>
|
||||
String -- ^ Consumer Key
|
||||
-> String -- ^ Consumer Secret
|
||||
authTwitter :: YesodAuth m
|
||||
=> ByteString -- ^ Consumer Key
|
||||
-> ByteString -- ^ Consumer Secret
|
||||
-> AuthPlugin m
|
||||
authTwitter = authOAuth "twitter"
|
||||
"screen_name"
|
||||
"http://twitter.com/oauth/request_token"
|
||||
"http://twitter.com/oauth/access_token"
|
||||
"http://twitter.com/oauth/authorize"
|
||||
authTwitter key secret = authOAuth
|
||||
(newOAuth { oauthServerName = "twitter"
|
||||
, oauthRequestUri = "https://api.twitter.com/oauth/request_token"
|
||||
, oauthAccessTokenUri = "https://api.twitter.com/oauth/access_token"
|
||||
, oauthAuthorizeUri = "https://api.twitter.com/oauth/authorize"
|
||||
, oauthSignatureMethod = HMACSHA1
|
||||
, oauthConsumerKey = key
|
||||
, oauthConsumerSecret = secret
|
||||
, oauthVersion = OAuth10a
|
||||
})
|
||||
extractCreds
|
||||
where
|
||||
extractCreds (Credential dic) = do
|
||||
let crId = decodeUtf8With lenientDecode $ fromJust $ lookup "screen_name" dic
|
||||
return $ Creds "twitter" crId $ map (bsToText *** bsToText ) dic
|
||||
|
||||
twitterUrl :: AuthRoute
|
||||
twitterUrl = oauthUrl "twitter"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
name: yesod-auth-oauth
|
||||
version: 0.8.0
|
||||
version: 0.8.1
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
author: Hiromi Ishii
|
||||
@ -21,12 +21,13 @@ library
|
||||
cpp-options: -DGHC7
|
||||
else
|
||||
build-depends: base >= 4 && < 4.3
|
||||
build-depends: authenticate-oauth >= 1.0 && < 1.1
|
||||
build-depends: authenticate-oauth >= 1.1 && < 1.2
|
||||
, bytestring >= 0.9.1.4 && < 0.10
|
||||
, yesod-core >= 0.10 && < 0.11
|
||||
, yesod-auth >= 0.8 && < 0.9
|
||||
, text >= 0.7 && < 0.12
|
||||
, hamlet >= 0.10 && < 0.11
|
||||
, conduit >= 0.2 && < 0.3
|
||||
, yesod-form >= 0.4 && < 0.5
|
||||
|
||||
exposed-modules: Yesod.Auth.OAuth
|
||||
|
||||
@ -18,7 +18,6 @@ module Yesod.Auth.GoogleEmail
|
||||
import Yesod.Auth
|
||||
import qualified Web.Authenticate.OpenId as OpenId
|
||||
|
||||
import Yesod.Form
|
||||
import Yesod.Handler
|
||||
import Yesod.Widget
|
||||
import Yesod.Request
|
||||
@ -31,45 +30,36 @@ import Control.Exception.Lifted (try, SomeException)
|
||||
forwardUrl :: AuthRoute
|
||||
forwardUrl = PluginR "googleemail" ["forward"]
|
||||
|
||||
googleIdent :: Text
|
||||
googleIdent = "https://www.google.com/accounts/o8/id"
|
||||
|
||||
authGoogleEmail :: YesodAuth m => AuthPlugin m
|
||||
authGoogleEmail =
|
||||
AuthPlugin "googleemail" dispatch login
|
||||
where
|
||||
complete = PluginR "googleemail" ["complete"]
|
||||
name = "openid_identifier"
|
||||
login tm = do
|
||||
[whamlet|
|
||||
<form method=get action=@{tm forwardUrl}>
|
||||
<input type=hidden name=openid_identifier value=https://www.google.com/accounts/o8/id>
|
||||
<input type=submit value=_{Msg.LoginGoogle}>
|
||||
|]
|
||||
login tm =
|
||||
[whamlet|<a href=@{tm forwardUrl}>_{Msg.LoginGoogle}|]
|
||||
dispatch "GET" ["forward"] = do
|
||||
roid <- runInputGet $ iopt textField name
|
||||
case roid of
|
||||
Just oid -> do
|
||||
render <- getUrlRender
|
||||
toMaster <- getRouteToMaster
|
||||
let complete' = render $ toMaster complete
|
||||
master <- getYesod
|
||||
eres <- lift $ try $ OpenId.getForwardUrl oid complete' Nothing
|
||||
[ ("openid.ax.type.email", "http://schema.openid.net/contact/email")
|
||||
, ("openid.ns.ax", "http://openid.net/srv/ax/1.0")
|
||||
, ("openid.ns.ax.required", "email")
|
||||
, ("openid.ax.mode", "fetch_request")
|
||||
, ("openid.ax.required", "email")
|
||||
, ("openid.ui.icon", "true")
|
||||
] (authHttpManager master)
|
||||
either
|
||||
(\err -> do
|
||||
setMessage $ toHtml $ show (err :: SomeException)
|
||||
redirect $ toMaster LoginR
|
||||
)
|
||||
redirect
|
||||
eres
|
||||
Nothing -> do
|
||||
toMaster <- getRouteToMaster
|
||||
setMessageI Msg.NoOpenID
|
||||
render <- getUrlRender
|
||||
toMaster <- getRouteToMaster
|
||||
let complete' = render $ toMaster complete
|
||||
master <- getYesod
|
||||
eres <- lift $ try $ OpenId.getForwardUrl googleIdent complete' Nothing
|
||||
[ ("openid.ax.type.email", "http://schema.openid.net/contact/email")
|
||||
, ("openid.ns.ax", "http://openid.net/srv/ax/1.0")
|
||||
, ("openid.ns.ax.required", "email")
|
||||
, ("openid.ax.mode", "fetch_request")
|
||||
, ("openid.ax.required", "email")
|
||||
, ("openid.ui.icon", "true")
|
||||
] (authHttpManager master)
|
||||
either
|
||||
(\err -> do
|
||||
setMessage $ toHtml $ show (err :: SomeException)
|
||||
redirect $ toMaster LoginR
|
||||
)
|
||||
redirect
|
||||
eres
|
||||
dispatch "GET" ["complete", ""] = dispatch "GET" ["complete"] -- compatibility issues
|
||||
dispatch "GET" ["complete"] = do
|
||||
rr <- getRequest
|
||||
|
||||
@ -6,6 +6,8 @@ module Yesod.Auth.Message
|
||||
-- * All languages
|
||||
, englishMessage
|
||||
, portugueseMessage
|
||||
, swedishMessage
|
||||
, germanMessage
|
||||
) where
|
||||
|
||||
import Data.Monoid (mappend)
|
||||
@ -113,3 +115,71 @@ portugueseMessage NowLoggedIn = "Você acaba de entrar no site com sucesso!"
|
||||
portugueseMessage LoginTitle = "Entrar no site"
|
||||
portugueseMessage PleaseProvideUsername = "Por favor digite seu nome de usuário"
|
||||
portugueseMessage PleaseProvidePassword = "Por favor digite sua senha"
|
||||
|
||||
swedishMessage :: AuthMessage -> Text
|
||||
swedishMessage NoOpenID = "Fann ej OpenID identifierare"
|
||||
swedishMessage LoginOpenID = "Logga in via OpenID"
|
||||
swedishMessage LoginGoogle = "Logga in via Google"
|
||||
swedishMessage LoginYahoo = "Logga in via Yahoo"
|
||||
swedishMessage Email = "Epost"
|
||||
swedishMessage Password = "Lösenord"
|
||||
swedishMessage Register = "Registrera"
|
||||
swedishMessage RegisterLong = "Registrera ett nytt konto"
|
||||
swedishMessage EnterEmail = "Skriv in din epost nedan så kommer ett konfirmationsmail skickas till adressen."
|
||||
swedishMessage ConfirmationEmailSentTitle = "Konfirmationsmail skickat"
|
||||
swedishMessage (ConfirmationEmailSent email) =
|
||||
"Ett konfirmationsmeddelande har skickats till" `mappend`
|
||||
email `mappend`
|
||||
"."
|
||||
swedishMessage AddressVerified = "Adress verifierad, vänligen välj nytt lösenord"
|
||||
swedishMessage InvalidKeyTitle = "Ogiltig verifikationsnyckel"
|
||||
swedishMessage InvalidKey = "Tyvärr, du angav en ogiltig verifimationsnyckel."
|
||||
swedishMessage InvalidEmailPass = "Ogiltig epost/lösenord kombination"
|
||||
swedishMessage BadSetPass = "Du måste vara inloggad för att ange ett lösenord"
|
||||
swedishMessage SetPassTitle = "Ange lösenord"
|
||||
swedishMessage SetPass = "Ange nytt lösenord"
|
||||
swedishMessage NewPass = "Nytt lösenord"
|
||||
swedishMessage ConfirmPass = "Godkänn"
|
||||
swedishMessage PassMismatch = "Lösenorden matcha ej, vänligen försök igen"
|
||||
swedishMessage PassUpdated = "Lösenord updaterades"
|
||||
swedishMessage Facebook = "Logga in med Facebook"
|
||||
swedishMessage LoginViaEmail = "Logga in via epost"
|
||||
swedishMessage InvalidLogin = "Ogiltigt login"
|
||||
swedishMessage NowLoggedIn = "Du är nu inloggad"
|
||||
swedishMessage LoginTitle = "Logga in"
|
||||
swedishMessage PleaseProvideUsername = "Vänligen fyll i användarnamn"
|
||||
swedishMessage PleaseProvidePassword = "Vänligen fyll i lösenord"
|
||||
|
||||
germanMessage :: AuthMessage -> Text
|
||||
germanMessage NoOpenID = "Kein OpenID-Identifier gefunden"
|
||||
germanMessage LoginOpenID = "Login via OpenID"
|
||||
germanMessage LoginGoogle = "Login via Google"
|
||||
germanMessage LoginYahoo = "Login via Yahoo"
|
||||
germanMessage Email = "Email"
|
||||
germanMessage Password = "Passwort"
|
||||
germanMessage Register = "Registrieren"
|
||||
germanMessage RegisterLong = "Neuen Account registrieren"
|
||||
germanMessage EnterEmail = "Bitte die e-Mail Adresse angeben, eine Bestätigungsmail wird verschickt."
|
||||
germanMessage ConfirmationEmailSentTitle = "Bestätigung verschickt."
|
||||
germanMessage (ConfirmationEmailSent email) =
|
||||
"Eine Bestätigung wurde an " `mappend`
|
||||
email `mappend`
|
||||
"versandt."
|
||||
germanMessage AddressVerified = "Adresse bestätigt, bitte neues Passwort angeben"
|
||||
germanMessage InvalidKeyTitle = "Ungültiger Bestätigungsschlüssel"
|
||||
germanMessage InvalidKey = "Das war leider ein ungültiger Bestätigungsschlüssel"
|
||||
germanMessage InvalidEmailPass = "Ungültiger Nutzername oder Passwort"
|
||||
germanMessage BadSetPass = "Um das Passwort zu ändern muss man eingeloggt sein"
|
||||
germanMessage SetPassTitle = "Passwort angeben"
|
||||
germanMessage SetPass = "Neues Passwort angeben"
|
||||
germanMessage NewPass = "Neues Passwort"
|
||||
germanMessage ConfirmPass = "Bestätigen"
|
||||
germanMessage PassMismatch = "Die Passwörter stimmten nicht überein"
|
||||
germanMessage PassUpdated = "Passwort überschrieben"
|
||||
germanMessage Facebook = "Login über Facebook"
|
||||
germanMessage LoginViaEmail = "Login via e-Mail"
|
||||
germanMessage InvalidLogin = "Ungültiger Login"
|
||||
germanMessage NowLoggedIn = "Login erfolgreich"
|
||||
germanMessage LoginTitle = "Login"
|
||||
germanMessage PleaseProvideUsername = "Bitte Nutzername angeben"
|
||||
germanMessage PleaseProvidePassword = "Bitte Passwort angeben"
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
import Yesod
|
||||
import Yesod.Auth
|
||||
import Yesod.Form
|
||||
import Yesod.Auth.Kerberos
|
||||
|
||||
data Kerberos = Kerberos
|
||||
|
||||
mkYesod "Kerberos" [parseRoutes|
|
||||
/ RootR GET
|
||||
/after AfterLoginR GET
|
||||
/auth AuthR Auth getAuth
|
||||
|]
|
||||
|
||||
getRootR :: Handler ()
|
||||
getRootR = redirect RedirectTemporary $ AuthR LoginR
|
||||
|
||||
getAfterLoginR :: Handler RepHtml
|
||||
getAfterLoginR = defaultLayout $ return ()
|
||||
|
||||
instance Yesod Kerberos where
|
||||
approot _ = "http://localhost:3000"
|
||||
|
||||
instance YesodAuth Kerberos where
|
||||
type AuthId Kerberos = String
|
||||
loginDest _ = AfterLoginR
|
||||
logoutDest _ = AuthR LoginR
|
||||
getAuthId _ = do
|
||||
liftIO $ putStrLn "getAuthId"
|
||||
return $ Just "foo"
|
||||
authPlugins = [authKerberos]
|
||||
|
||||
instance RenderMessage Kerberos FormMessage where
|
||||
renderMessage _ _ = defaultFormMessage
|
||||
|
||||
main :: IO ()
|
||||
main = warpDebug 3000 Kerberos
|
||||
@ -1,5 +1,5 @@
|
||||
name: yesod-auth
|
||||
version: 0.8.1
|
||||
version: 0.8.1.1
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
author: Michael Snoyman, Patrick Brisbin
|
||||
|
||||
@ -19,6 +19,7 @@ module Yesod.Content
|
||||
, typeJpeg
|
||||
, typePng
|
||||
, typeGif
|
||||
, typeSvg
|
||||
, typeJavascript
|
||||
, typeCss
|
||||
, typeFlv
|
||||
@ -196,6 +197,9 @@ typePng = "image/png"
|
||||
typeGif :: ContentType
|
||||
typeGif = "image/gif"
|
||||
|
||||
typeSvg :: ContentType
|
||||
typeSvg = "image/svg+xml"
|
||||
|
||||
typeJavascript :: ContentType
|
||||
typeJavascript = "text/javascript; charset=utf-8"
|
||||
|
||||
|
||||
@ -33,6 +33,10 @@ module Yesod.Core
|
||||
, clientSessionBackend
|
||||
, saveClientSession
|
||||
, loadClientSession
|
||||
-- * JS loaders
|
||||
, loadJsYepnope
|
||||
, ScriptLoadPosition (..)
|
||||
, BottomOfHeadAsync
|
||||
-- * Misc
|
||||
, yesodVersion
|
||||
, yesodRender
|
||||
|
||||
@ -31,6 +31,10 @@ module Yesod.Internal.Core
|
||||
, clientSessionBackend
|
||||
, saveClientSession
|
||||
, loadClientSession
|
||||
-- * jsLoader
|
||||
, ScriptLoadPosition (..)
|
||||
, BottomOfHeadAsync
|
||||
, loadJsYepnope
|
||||
-- * Misc
|
||||
, yesodVersion
|
||||
, yesodRender
|
||||
@ -321,11 +325,23 @@ class RenderRoute a => Yesod a where
|
||||
gzipSettings :: a -> GzipSettings
|
||||
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.
|
||||
yepnopeJs :: a -> Maybe (Either Text (Route a))
|
||||
yepnopeJs _ = Nothing
|
||||
|
||||
-- | Where to Load sripts from. We recommend changing this to 'BottomOfBody'
|
||||
-- Alternatively use the built in async yepnope loader:
|
||||
--
|
||||
-- > BottomOfHeadAsync $ loadJsYepnope $ Right $ StaticR js_modernizr_js
|
||||
--
|
||||
-- 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)
|
||||
|
||||
-- | Create a session backend. Returning `Nothing' disables sessions.
|
||||
makeSessionBackend :: a -> IO (Maybe (SessionBackend a))
|
||||
makeSessionBackend a = do
|
||||
@ -578,7 +594,17 @@ widgetToPageContent w = do
|
||||
|
||||
-- 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
|
||||
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|
|
||||
\^{head'}
|
||||
$forall s <- stylesheets
|
||||
@ -594,31 +620,22 @@ $forall s <- css
|
||||
<style media=#{media}>#{content}
|
||||
$nothing
|
||||
<style>#{content}
|
||||
$maybe eyn <- yepnopeJs master
|
||||
$maybe yn <- left eyn
|
||||
<script src=#{yn}>
|
||||
$maybe yn <- right eyn
|
||||
<script src=@{yn}>
|
||||
$maybe complete <- mcomplete
|
||||
<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}
|
||||
$case jsLoader master
|
||||
$of BottomOfBody
|
||||
$of BottomOfHeadAsync asyncJsLoader
|
||||
^{asyncJsLoader asyncScripts mcomplete}
|
||||
$of BottomOfHeadBlocking
|
||||
^{regularScriptLoad}
|
||||
|]
|
||||
let bodyScript = [HAMLET|
|
||||
^{body}
|
||||
^{regularScriptLoad}
|
||||
|]
|
||||
return $ PageContent title headAll body
|
||||
where
|
||||
left (Left x) = Just x
|
||||
left _ = Nothing
|
||||
right (Right x) = Just x
|
||||
right _ = Nothing
|
||||
|
||||
return $ PageContent title headAll (case jsLoader master of
|
||||
BottomOfBody -> bodyScript
|
||||
_ -> body)
|
||||
where
|
||||
renderLoc' render' (Local url) = render' url []
|
||||
renderLoc' _ (Remote s) = s
|
||||
|
||||
@ -632,13 +649,48 @@ $nothing
|
||||
: attrs
|
||||
)
|
||||
|
||||
ynHelper :: (url -> [x] -> Text)
|
||||
data ScriptLoadPosition master
|
||||
= BottomOfBody
|
||||
| BottomOfHeadBlocking
|
||||
| BottomOfHeadAsync (BottomOfHeadAsync master)
|
||||
|
||||
type BottomOfHeadAsync master
|
||||
= [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)]
|
||||
-> Maybe (JavascriptUrl (url))
|
||||
-> Maybe Text
|
||||
-> (Maybe (HtmlUrl (url)), Html)
|
||||
ynHelper render scripts jscript jsLoc =
|
||||
(mcomplete, unsafeLazyByteString $ encode $ Array $ Vector.fromList $ map String scripts'')
|
||||
-> (Maybe (HtmlUrl url), [Text])
|
||||
asyncHelper render scripts jscript jsLoc =
|
||||
(mcomplete, scripts'')
|
||||
where
|
||||
scripts' = map goScript scripts
|
||||
scripts'' =
|
||||
|
||||
@ -10,6 +10,7 @@ import YesodCoreTest.InternalRequest
|
||||
import YesodCoreTest.ErrorHandling
|
||||
import YesodCoreTest.Cache
|
||||
import qualified YesodCoreTest.Redirect as Redirect
|
||||
import qualified YesodCoreTest.JsLoader as JsLoader
|
||||
|
||||
import Test.Hspec
|
||||
|
||||
@ -25,4 +26,5 @@ specs =
|
||||
, errorHandlingTest
|
||||
, cacheTest
|
||||
, Redirect.specs
|
||||
, JsLoader.specs
|
||||
]
|
||||
|
||||
40
yesod-core/test/YesodCoreTest/JsLoader.hs
Normal file
40
yesod-core/test/YesodCoreTest/JsLoader.hs
Normal file
@ -0,0 +1,40 @@
|
||||
{-# LANGUAGE QuasiQuotes, TypeFamilies, TemplateHaskell, MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
module YesodCoreTest.JsLoader (specs) where
|
||||
|
||||
import YesodCoreTest.JsLoaderSites.HeadAsync (HA(..))
|
||||
import YesodCoreTest.JsLoaderSites.Bottom (B(..))
|
||||
|
||||
import Test.Hspec
|
||||
import Test.Hspec.HUnit ()
|
||||
|
||||
import Yesod.Core hiding (Request)
|
||||
import Network.Wai.Test
|
||||
|
||||
data H = H
|
||||
mkYesod "H" [parseRoutes|
|
||||
/ HeadR GET
|
||||
|]
|
||||
instance Yesod H
|
||||
|
||||
getHeadR :: Handler RepHtml
|
||||
getHeadR = defaultLayout $ addScriptRemote "load.js"
|
||||
|
||||
specs :: [Spec]
|
||||
specs = describe "Test.Links" [
|
||||
it "link from head" $ runner H $ do
|
||||
res <- request defaultRequest
|
||||
assertBody "<!DOCTYPE html>\n<html><head><title></title><script src=\"load.js\"></script></head><body></body></html>" res
|
||||
|
||||
, it "link from head async" $ runner HA $ do
|
||||
res <- request defaultRequest
|
||||
assertBody "<!DOCTYPE html>\n<html><head><title></title><script src=\"yepnope.js\"></script><script>yepnope({load:[\"load.js\"]});</script></head><body></body></html>" res
|
||||
|
||||
, it "link from bottom" $ runner B $ do
|
||||
res <- request defaultRequest
|
||||
assertBody "<!DOCTYPE html>\n<html><head><title></title></head><body><script src=\"load.js\"></script></body></html>" res
|
||||
]
|
||||
|
||||
runner :: (YesodDispatch master master, Yesod master) => master -> Session () -> IO ()
|
||||
runner app f = toWaiApp app >>= runSession f
|
||||
17
yesod-core/test/YesodCoreTest/JsLoaderSites/Bottom.hs
Normal file
17
yesod-core/test/YesodCoreTest/JsLoaderSites/Bottom.hs
Normal file
@ -0,0 +1,17 @@
|
||||
{-# LANGUAGE QuasiQuotes, TypeFamilies, TemplateHaskell, MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
module YesodCoreTest.JsLoaderSites.Bottom (B(..)) where
|
||||
|
||||
import Yesod.Core
|
||||
|
||||
data B = B
|
||||
mkYesod "B" [parseRoutes|
|
||||
/ BottomR GET
|
||||
|]
|
||||
instance Yesod B where
|
||||
jsLoader _ = BottomOfBody
|
||||
|
||||
getBottomR :: Handler RepHtml
|
||||
getBottomR = defaultLayout $ addScriptRemote "load.js"
|
||||
|
||||
16
yesod-core/test/YesodCoreTest/JsLoaderSites/HeadAsync.hs
Normal file
16
yesod-core/test/YesodCoreTest/JsLoaderSites/HeadAsync.hs
Normal file
@ -0,0 +1,16 @@
|
||||
{-# LANGUAGE QuasiQuotes, TypeFamilies, TemplateHaskell, MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
module YesodCoreTest.JsLoaderSites.HeadAsync (HA(..)) where
|
||||
|
||||
import Yesod.Core
|
||||
|
||||
data HA = HA
|
||||
mkYesod "HA" [parseRoutes|
|
||||
/ HeadAsyncR GET
|
||||
|]
|
||||
instance Yesod HA where
|
||||
jsLoader _ = BottomOfHeadAsync $ loadJsYepnope $ Left "yepnope.js"
|
||||
|
||||
getHeadAsyncR :: Handler RepHtml
|
||||
getHeadAsyncR = defaultLayout $ addScriptRemote "load.js"
|
||||
@ -1,5 +1,5 @@
|
||||
name: yesod-core
|
||||
version: 0.10.1
|
||||
version: 0.10.2.2
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
author: Michael Snoyman <michael@snoyman.com>
|
||||
@ -49,13 +49,13 @@ library
|
||||
build-depends: time >= 1.1.4
|
||||
, yesod-routes >= 0.0.1 && < 0.1
|
||||
, wai >= 1.1 && < 1.2
|
||||
, wai-extra >= 1.1 && < 1.2
|
||||
, wai-extra >= 1.1 && < 1.3
|
||||
, bytestring >= 0.9.1.4 && < 0.10
|
||||
, text >= 0.7 && < 0.12
|
||||
, template-haskell
|
||||
, path-pieces >= 0.1 && < 0.2
|
||||
, hamlet >= 0.10.7 && < 0.11
|
||||
, shakespeare >= 0.10 && < 0.11
|
||||
, shakespeare >= 0.10 && < 0.12
|
||||
, shakespeare-js >= 0.11 && < 0.12
|
||||
, shakespeare-css >= 0.10.5 && < 0.11
|
||||
, shakespeare-i18n >= 0.0 && < 0.1
|
||||
|
||||
@ -7,6 +7,7 @@ module Yesod.Default.Util
|
||||
, globFile
|
||||
, widgetFileNoReload
|
||||
, widgetFileReload
|
||||
, widgetFileJsCss
|
||||
) where
|
||||
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
@ -72,8 +73,21 @@ widgetFileReload x = do
|
||||
let l = whenExists x "lucius" luciusFileReload
|
||||
[|$h >> addCassius $c >> addJulius $j >> addLucius $l|]
|
||||
|
||||
widgetFileJsCss :: (String, FilePath -> Q Exp) -- ^ Css file extenstion and loading function. example: ("cassius", cassiusFileReload)
|
||||
-> (String, FilePath -> Q Exp) -- ^ Css file extenstion and loading function. example: ("julius", juliusFileReload)
|
||||
-> FilePath -> Q Exp
|
||||
widgetFileJsCss (jsExt, jsLoad) (csExt, csLoad) x = do
|
||||
let h = whenExists x "hamlet" whamletFile
|
||||
let c = whenExists x csExt csLoad
|
||||
let j = whenExists x jsExt jsLoad
|
||||
[|$h >> addCassius $c >> addJulius $j|]
|
||||
|
||||
whenExists :: String -> String -> (FilePath -> Q Exp) -> Q Exp
|
||||
whenExists x glob f = do
|
||||
whenExists = warnUnlessExists False
|
||||
|
||||
warnUnlessExists :: Bool -> String -> String -> (FilePath -> Q Exp) -> Q Exp
|
||||
warnUnlessExists shouldWarn x glob f = do
|
||||
let fn = globFile glob x
|
||||
e <- qRunIO $ doesFileExist fn
|
||||
unless (shouldWarn && e) $ qRunIO $ putStrLn $ "widget file not found: " ++ fn
|
||||
if e then f fn else [|mempty|]
|
||||
|
||||
@ -21,7 +21,7 @@ library
|
||||
, yesod-core >= 0.10.1&& < 0.11
|
||||
, warp >= 1.1 && < 1.2
|
||||
, wai >= 1.1 && < 1.2
|
||||
, wai-extra >= 1.1 && < 1.2
|
||||
, wai-extra >= 1.1 && < 1.3
|
||||
, bytestring >= 0.9.1.4
|
||||
, transformers >= 0.2.2 && < 0.3
|
||||
, text >= 0.9
|
||||
|
||||
@ -173,7 +173,7 @@ htmlField = Field
|
||||
}
|
||||
where showVal = either id (pack . renderHtml)
|
||||
|
||||
-- | A newtype wrapper around a 'String' that converts newlines to HTML
|
||||
-- | A newtype wrapper around a 'Text' that converts newlines to HTML
|
||||
-- br-tags.
|
||||
newtype Textarea = Textarea { unTextarea :: Text }
|
||||
deriving (Show, Read, Eq, PersistField)
|
||||
|
||||
@ -297,17 +297,17 @@ $forall view <- views
|
||||
--
|
||||
-- Sample Hamlet:
|
||||
--
|
||||
-- > <form method=post action=@{ActionR} enctype=#{formEnctype}>
|
||||
-- > <fieldset>
|
||||
-- > <legend>_{MsgLegend}
|
||||
-- > $case result
|
||||
-- > $of FormFailure reasons
|
||||
-- > $forall reason <- reasons
|
||||
-- > <div .alert-message .error>#{reason}
|
||||
-- > $of _
|
||||
-- > ^{formWidget}
|
||||
-- > <div .actions>
|
||||
-- > <input .btn .primary type=submit value=_{MsgSubmit}>
|
||||
-- > <form .form-horizontal method=post action=@{ActionR} enctype=#{formEnctype}>
|
||||
-- > <fieldset>
|
||||
-- > <legend>_{MsgLegend}
|
||||
-- > $case result
|
||||
-- > $of FormFailure reasons
|
||||
-- > $forall reason <- reasons
|
||||
-- > <div .alert .alert-error>#{reason}
|
||||
-- > $of _
|
||||
-- > ^{formWidget}
|
||||
-- > <div .form-actions>
|
||||
-- > <input .btn .primary type=submit value=_{MsgSubmit}>
|
||||
renderBootstrap :: FormRender sub master a
|
||||
renderBootstrap aform fragment = do
|
||||
(res, views') <- aFormToForm aform
|
||||
@ -317,9 +317,9 @@ renderBootstrap aform fragment = do
|
||||
let widget = [whamlet|
|
||||
\#{fragment}
|
||||
$forall view <- views
|
||||
<div .clearfix :fvRequired view:.required :not $ fvRequired view:.optional :has $ fvErrors view:.error>
|
||||
<label for=#{fvId view}>#{fvLabel view}
|
||||
<div.input>
|
||||
<div .control-group .clearfix :fvRequired view:.required :not $ fvRequired view:.optional :has $ fvErrors view:.error>
|
||||
<label .control-label for=#{fvId view}>#{fvLabel view}
|
||||
<div .controls .input>
|
||||
^{fvInput view}
|
||||
$maybe tt <- fvTooltip view
|
||||
<span .help-block>#{tt}
|
||||
|
||||
@ -16,7 +16,7 @@ germanFormMessage (MsgInvalidEmail t) = "Ungültige e-Mail Adresse: " `mappend`
|
||||
germanFormMessage (MsgInvalidHour t) = "Ungültige Stunde: " `mappend` t
|
||||
germanFormMessage (MsgInvalidMinute t) = "Ungültige Minute: " `mappend` t
|
||||
germanFormMessage (MsgInvalidSecond t) = "Ungültige Sekunde: " `mappend` t
|
||||
germanFormMessage MsgCsrfWarning = "Bitte bestätigen Sie ihre Eingabe, als Schutz gegen Cross-Site Forgery Angriffen"
|
||||
germanFormMessage MsgCsrfWarning = "Bitte bestätigen Sie ihre Eingabe, als Schutz gegen Cross-Site Forgery Angriffe"
|
||||
germanFormMessage MsgValueRequired = "Wert wird benötigt"
|
||||
germanFormMessage (MsgInputNotFound t) = "Eingabe nicht gefunden: " `mappend` t
|
||||
germanFormMessage MsgSelectNone = "<Nichts>"
|
||||
|
||||
@ -11,7 +11,7 @@ module Yesod.Form.Nic
|
||||
) where
|
||||
|
||||
import Yesod.Handler
|
||||
import Yesod.Core (Route, yepnopeJs, Yesod)
|
||||
import Yesod.Core (Route, ScriptLoadPosition(..), jsLoader, Yesod)
|
||||
import Yesod.Form
|
||||
import Yesod.Widget
|
||||
import Text.HTML.SanitizeXSS (sanitizeBalance)
|
||||
@ -43,8 +43,8 @@ nicHtmlField = Field
|
||||
addScript' urlNicEdit
|
||||
master <- lift getYesod
|
||||
addJulius $
|
||||
case yepnopeJs master of
|
||||
Nothing ->
|
||||
case jsLoader master of
|
||||
BottomOfHeadBlocking ->
|
||||
#if __GLASGOW_HASKELL__ >= 700
|
||||
[julius|
|
||||
#else
|
||||
@ -52,7 +52,7 @@ nicHtmlField = Field
|
||||
#endif
|
||||
bkLib.onDomLoaded(function(){new nicEditor({fullPanel:true}).panelInstance("#{theId}")});
|
||||
|]
|
||||
Just _ ->
|
||||
_ ->
|
||||
#if __GLASGOW_HASKELL__ >= 700
|
||||
[julius|
|
||||
#else
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
name: yesod-form
|
||||
version: 0.4.1
|
||||
version: 0.4.2.1
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
author: Michael Snoyman <michael@snoyman.com>
|
||||
@ -14,7 +14,7 @@ description: Form handling support for Yesod Web Framework
|
||||
|
||||
library
|
||||
build-depends: base >= 4 && < 5
|
||||
, yesod-core >= 0.10.1 && < 0.11
|
||||
, yesod-core >= 0.10.2 && < 0.11
|
||||
, yesod-persistent >= 0.3.1 && < 0.4
|
||||
, time >= 1.1.4
|
||||
, hamlet >= 0.10 && < 0.11
|
||||
|
||||
@ -26,7 +26,7 @@ library
|
||||
, conduit >= 0.2 && < 0.3
|
||||
, transformers >= 0.2.2 && < 0.3
|
||||
, wai >= 1.1 && < 1.2
|
||||
, wai-extra >= 1.1 && < 1.2
|
||||
, wai-extra >= 1.1 && < 1.3
|
||||
, bytestring >= 0.9 && < 0.10
|
||||
, safe >= 0.2 && < 0.4
|
||||
exposed-modules: Yesod.Json
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
module Yesod.Routes.TH.RenderRoute
|
||||
( -- ** RenderRoute
|
||||
mkRenderRouteInstance
|
||||
, mkRenderRouteInstance'
|
||||
, mkRouteCons
|
||||
, mkRenderRouteClauses
|
||||
) where
|
||||
@ -89,12 +90,19 @@ mkRenderRouteClauses =
|
||||
|
||||
-- | Generate the 'RenderRoute' instance.
|
||||
--
|
||||
-- This includes both the 'Route' associated type and the 'renderRoute' method.
|
||||
-- This function uses both 'mkRouteCons' and 'mkRenderRouteClasses'.
|
||||
-- This includes both the 'Route' associated type and the
|
||||
-- 'renderRoute' method. This function uses both 'mkRouteCons' and
|
||||
-- 'mkRenderRouteClasses'.
|
||||
mkRenderRouteInstance :: Type -> [Resource Type] -> Q Dec
|
||||
mkRenderRouteInstance typ ress = do
|
||||
mkRenderRouteInstance = mkRenderRouteInstance' []
|
||||
|
||||
-- | A more general version of 'mkRenderRouteInstance' which takes an
|
||||
-- additional context.
|
||||
|
||||
mkRenderRouteInstance' :: Cxt -> Type -> [Resource Type] -> Q Dec
|
||||
mkRenderRouteInstance' cxt typ ress = do
|
||||
cls <- mkRenderRouteClauses ress
|
||||
return $ InstanceD [] (ConT ''RenderRoute `AppT` typ)
|
||||
return $ InstanceD cxt (ConT ''RenderRoute `AppT` typ)
|
||||
[ DataInstD [] ''Route [typ] (mkRouteCons ress) clazzes
|
||||
, FunD (mkName "renderRoute") cls
|
||||
]
|
||||
|
||||
@ -138,8 +138,12 @@ determineHamletDeps x = do
|
||||
<|> (A.string "$(widgetFile " >> return Hamlet)
|
||||
<|> (A.string "$(Settings.hamletFile " >> return Hamlet)
|
||||
<|> (A.string "$(Settings.widgetFile " >> return Hamlet)
|
||||
<|> (A.string "$(persistFile " >> return Verbatim)
|
||||
<|> (A.string "$(parseRoutesFile " >> return Verbatim)
|
||||
<|> (A.string "$(persistFile " >> return Verbatim)
|
||||
<|> (
|
||||
A.string "$(persistFileWith " >>
|
||||
A.many1 (A.satisfy (/= '"')) >>
|
||||
return Verbatim)
|
||||
<|> (do
|
||||
_ <- A.string "\nmkMessage \""
|
||||
A.skipWhile (/= '"')
|
||||
|
||||
180
yesod/Devel.hs
180
yesod/Devel.hs
@ -12,31 +12,27 @@ import qualified Distribution.Simple.Utils as D
|
||||
import qualified Distribution.Verbosity as D
|
||||
import qualified Distribution.PackageDescription.Parse as D
|
||||
import qualified Distribution.PackageDescription as D
|
||||
import qualified Distribution.ModuleName as D
|
||||
|
||||
import Control.Concurrent (forkIO, threadDelay)
|
||||
import qualified Control.Exception as Ex
|
||||
import Control.Monad (forever)
|
||||
import Control.Monad (forever, when)
|
||||
|
||||
import Data.Char (isUpper, isNumber)
|
||||
import qualified Data.List as L
|
||||
import qualified Data.Map as Map
|
||||
import Data.Maybe (listToMaybe)
|
||||
import qualified Data.Set as Set
|
||||
|
||||
import System.Directory (createDirectoryIfMissing, removeFile,
|
||||
getDirectoryContents)
|
||||
import System.Exit (exitFailure, exitSuccess)
|
||||
import System.Directory
|
||||
import System.Exit (exitFailure, exitSuccess, ExitCode (..))
|
||||
import System.FilePath (splitDirectories, dropExtension, takeExtension)
|
||||
import System.Posix.Types (EpochTime)
|
||||
import System.PosixCompat.Files (modificationTime, getFileStatus)
|
||||
import System.Process (runCommand, terminateProcess,
|
||||
import System.Process (createProcess, proc, terminateProcess, readProcess,
|
||||
waitForProcess, rawSystem)
|
||||
|
||||
import Build (recompDeps, getDeps,findHaskellFiles)
|
||||
|
||||
#if __GLASGOW_HASKELL__ >= 700
|
||||
#define ST st
|
||||
#else
|
||||
#define ST $st
|
||||
#endif
|
||||
|
||||
lockFile :: FilePath
|
||||
lockFile = "dist/devel-terminate"
|
||||
|
||||
@ -48,8 +44,11 @@ writeLock = do
|
||||
removeLock :: IO ()
|
||||
removeLock = try_ (removeFile lockFile)
|
||||
|
||||
devel :: Bool -> IO ()
|
||||
devel isCabalDev = do
|
||||
devel :: Bool -> [String] -> IO ()
|
||||
devel isCabalDev passThroughArgs = do
|
||||
|
||||
checkDevelFile
|
||||
|
||||
writeLock
|
||||
|
||||
putStrLn "Yesod devel server. Press ENTER to quit"
|
||||
@ -59,71 +58,68 @@ devel isCabalDev = do
|
||||
|
||||
checkCabalFile gpd
|
||||
|
||||
_ <- if isCabalDev
|
||||
then rawSystem "cabal-dev"
|
||||
[ "configure"
|
||||
, "--cabal-install-arg=-fdevel" -- legacy
|
||||
, "--cabal-install-arg=-flibrary-only"
|
||||
, "--disable-library-profiling"
|
||||
]
|
||||
else rawSystem "cabal"
|
||||
[ "configure"
|
||||
, "-fdevel" -- legacy
|
||||
, "-flibrary-only"
|
||||
, "--disable-library-profiling"
|
||||
]
|
||||
_<- rawSystem cmd args
|
||||
|
||||
mainLoop isCabalDev
|
||||
mainLoop
|
||||
|
||||
_ <- getLine
|
||||
writeLock
|
||||
exitSuccess
|
||||
where
|
||||
cmd | isCabalDev == True = "cabal-dev"
|
||||
| otherwise = "cabal"
|
||||
|
||||
diffArgs | isCabalDev == True = [
|
||||
"--cabal-install-arg=-fdevel" -- legacy
|
||||
, "--cabal-install-arg=-flibrary-only"
|
||||
]
|
||||
| otherwise = [
|
||||
"-fdevel" -- legacy
|
||||
, "-flibrary-only"
|
||||
]
|
||||
args = "configure":diffArgs ++ ["--disable-library-profiling" ]
|
||||
|
||||
mainLoop :: IO ()
|
||||
mainLoop = do
|
||||
ghcVer <- ghcVersion
|
||||
forever $ do
|
||||
putStrLn "Rebuilding application..."
|
||||
|
||||
mainLoop :: Bool -> IO ()
|
||||
mainLoop isCabalDev = forever $ do
|
||||
putStrLn "Rebuilding application..."
|
||||
recompDeps
|
||||
|
||||
recompDeps
|
||||
list <- getFileList
|
||||
exit <- rawSystem cmd ["build"]
|
||||
|
||||
list <- getFileList
|
||||
_ <- if isCabalDev
|
||||
then rawSystem "cabal-dev" ["build"]
|
||||
else rawSystem "cabal" ["build"]
|
||||
|
||||
removeLock
|
||||
pkg <- pkgConfigs isCabalDev
|
||||
let start = concat ["runghc ", pkg, " devel.hs"]
|
||||
putStrLn $ "Starting development server: " ++ start
|
||||
ph <- runCommand start
|
||||
watchTid <- forkIO . try_ $ do
|
||||
watchForChanges list
|
||||
putStrLn "Stopping development server..."
|
||||
writeLock
|
||||
threadDelay 1000000
|
||||
putStrLn "Terminating development server..."
|
||||
terminateProcess ph
|
||||
ec <- waitForProcess ph
|
||||
putStrLn $ "Exit code: " ++ show ec
|
||||
Ex.throwTo watchTid (userError "process finished")
|
||||
watchForChanges list
|
||||
case exit of
|
||||
ExitFailure _ -> putStrLn "Build failure, pausing..."
|
||||
_ -> do
|
||||
removeLock
|
||||
let pkg = pkgConfigs isCabalDev ghcVer
|
||||
let dev_args = pkg ++ ["devel.hs"] ++ passThroughArgs
|
||||
putStrLn $ "Starting development server: runghc " ++ L.intercalate " " dev_args
|
||||
(_,_,_,ph) <- createProcess $ proc "runghc" dev_args
|
||||
watchTid <- forkIO . try_ $ do
|
||||
watchForChanges list
|
||||
putStrLn "Stopping development server..."
|
||||
writeLock
|
||||
threadDelay 1000000
|
||||
putStrLn "Terminating development server..."
|
||||
terminateProcess ph
|
||||
ec <- waitForProcess ph
|
||||
putStrLn $ "Exit code: " ++ show ec
|
||||
Ex.throwTo watchTid (userError "process finished")
|
||||
watchForChanges list
|
||||
|
||||
try_ :: forall a. IO a -> IO ()
|
||||
try_ x = (Ex.try x :: IO (Either Ex.SomeException a)) >> return ()
|
||||
|
||||
pkgConfigs :: Bool -> IO String
|
||||
pkgConfigs isDev
|
||||
| isDev = do
|
||||
devContents <- getDirectoryContents "cabal-dev"
|
||||
let confs = filter isConfig devContents
|
||||
return . unwords $ inplacePkg :
|
||||
map ("-package-confcabal-dev/"++) confs
|
||||
| otherwise = return inplacePkg
|
||||
pkgConfigs :: Bool -> String -> [String]
|
||||
pkgConfigs isCabalDev ghcVer
|
||||
| isCabalDev = ["-package-confcabal-dev/packages-" ++ ghcVer ++ ".conf", inplacePkg]
|
||||
| otherwise = [inplacePkg]
|
||||
where
|
||||
inplacePkg = "-package-confdist/package.conf.inplace"
|
||||
isConfig dir = "packages-" `L.isPrefixOf` dir &&
|
||||
".conf" `L.isSuffixOf` dir
|
||||
|
||||
|
||||
type FileList = Map.Map FilePath EpochTime
|
||||
|
||||
@ -143,29 +139,69 @@ watchForChanges list = do
|
||||
then return ()
|
||||
else threadDelay 1000000 >> watchForChanges list
|
||||
|
||||
checkDevelFile :: IO ()
|
||||
checkDevelFile = do
|
||||
e <- doesFileExist "devel.hs"
|
||||
when (not e) $ failWith "file devel.hs not found"
|
||||
|
||||
checkCabalFile :: D.GenericPackageDescription -> IO ()
|
||||
checkCabalFile gpd = case D.condLibrary gpd of
|
||||
Nothing -> do
|
||||
putStrLn "Error: incorrect cabal file, no library"
|
||||
exitFailure
|
||||
Nothing -> failWith "incorrect cabal file, no library"
|
||||
Just ct ->
|
||||
case lookupDevelLib ct of
|
||||
Nothing -> do
|
||||
putStrLn "Error: no development flag found in your configuration file. Expected a 'library-only' flag or the older 'devel' flag"
|
||||
exitFailure
|
||||
Just dLib ->
|
||||
Nothing ->
|
||||
failWith "no development flag found in your configuration file. Expected a 'library-only' flag or the older 'devel' flag"
|
||||
Just dLib -> do
|
||||
case (D.hsSourceDirs . D.libBuildInfo) dLib of
|
||||
[] -> return ()
|
||||
["."] -> return ()
|
||||
_ ->
|
||||
putStrLn $ "WARNING: yesod devel may not work correctly with " ++
|
||||
"custom hs-source-dirs"
|
||||
fl <- getFileList
|
||||
let unlisted = checkFileList fl dLib
|
||||
when (not . null $ unlisted) $ do
|
||||
putStrLn "WARNING: the following source files are not listed in exposed-modules or other-modules:"
|
||||
mapM_ putStrLn unlisted
|
||||
when (D.fromString "Application" `notElem` D.exposedModules dLib) $ do
|
||||
putStrLn "WARNING: no exposed module Application"
|
||||
|
||||
failWith :: String -> IO a
|
||||
failWith msg = do
|
||||
putStrLn $ "ERROR: " ++ msg
|
||||
exitFailure
|
||||
|
||||
checkFileList :: FileList -> D.Library -> [FilePath]
|
||||
checkFileList fl lib = filter isUnlisted . filter isSrcFile $ sourceFiles
|
||||
where
|
||||
al = allModules lib
|
||||
-- a file is only a possible 'module file' if all path pieces start with a capital letter
|
||||
sourceFiles = filter isSrcFile . map fst . Map.toList $ fl
|
||||
isSrcFile file = let dirs = filter (/=".") $ splitDirectories file
|
||||
in all (isUpper . head) dirs && (takeExtension file `elem` [".hs", ".lhs"])
|
||||
isUnlisted file = not (toModuleName file `Set.member` al)
|
||||
toModuleName = L.intercalate "." . filter (/=".") . splitDirectories . dropExtension
|
||||
|
||||
allModules :: D.Library -> Set.Set String
|
||||
allModules lib = Set.fromList $ map toString $ D.exposedModules lib ++ (D.otherModules . D.libBuildInfo) lib
|
||||
where
|
||||
toString = L.intercalate "." . D.components
|
||||
|
||||
ghcVersion :: IO String
|
||||
ghcVersion = fmap getNumber $ readProcess "runghc" ["--numeric-version", "0"] []
|
||||
where
|
||||
getNumber = filter (\x -> isNumber x || x == '.')
|
||||
|
||||
|
||||
lookupDevelLib :: D.CondTree D.ConfVar c a -> Maybe a
|
||||
lookupDevelLib ct = listToMaybe . map (\(_,x,_) -> D.condTreeData x) .
|
||||
filter isDevelLib . D.condTreeComponents $ ct
|
||||
lookupDevelLib ct | found = Just (D.condTreeData ct)
|
||||
| otherwise = Nothing
|
||||
where
|
||||
found = not . null . map (\(_,x,_) -> D.condTreeData x) .
|
||||
filter isDevelLib . D.condTreeComponents $ ct
|
||||
isDevelLib ((D.Var (D.Flag (D.FlagName f))), _, _) = f `elem` ["library-only", "devel"]
|
||||
isDevelLib _ = False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ main = do
|
||||
"build":rest -> touch >> build rest >>= exitWith
|
||||
["touch"] -> touch
|
||||
#endif
|
||||
["devel"] -> devel isDev
|
||||
"devel":rest -> devel isDev rest
|
||||
["version"] -> putStrLn yesodVersion
|
||||
"configure":rest -> rawSystem cmd ("configure":rest) >>= exitWith
|
||||
_ -> do
|
||||
|
||||
@ -1 +1,2 @@
|
||||
:set -i.:config:dist/build/autogen
|
||||
:set -XCPP -XTemplateHaskell -XQuasiQuotes -XTypeFamilies -XFlexibleContexts -XGADTs -XOverloadedStrings -XMultiParamTypeClasses -XGeneralizedNewtypeDeriving -XEmptyDataDecls
|
||||
|
||||
@ -6,7 +6,6 @@ module Application
|
||||
|
||||
import Import
|
||||
import Settings
|
||||
import Settings.StaticFiles (staticSite)
|
||||
import Yesod.Auth
|
||||
import Yesod.Default.Config
|
||||
import Yesod.Default.Main
|
||||
|
||||
@ -15,7 +15,6 @@ module Foundation
|
||||
import Prelude
|
||||
import Yesod
|
||||
import Yesod.Static
|
||||
import Settings.StaticFiles
|
||||
import Yesod.Auth
|
||||
import Yesod.Auth.BrowserId
|
||||
import Yesod.Auth.GoogleEmail
|
||||
@ -124,8 +123,8 @@ instance Yesod ~sitearg~ where
|
||||
-- users receiving stale content.
|
||||
addStaticContent = addStaticContentExternal minifym base64md5 Settings.staticDir (StaticR . flip StaticRoute [])
|
||||
|
||||
-- Enable Javascript async loading
|
||||
yepnopeJs _ = Just $ Right $ StaticR js_modernizr_js
|
||||
-- Place Javascript at bottom of the body tag so the rest of the page loads first
|
||||
jsLoader _ = BottomOfBody
|
||||
|
||||
-- How to run database actions.
|
||||
instance YesodPersist ~sitearg~ where
|
||||
|
||||
@ -2,19 +2,25 @@ module Import
|
||||
( module Prelude
|
||||
, module Yesod
|
||||
, module Foundation
|
||||
, (<>)
|
||||
, Text
|
||||
, module Settings.StaticFiles
|
||||
, module Data.Monoid
|
||||
, module Control.Applicative
|
||||
, Text
|
||||
#if __GLASGOW_HASKELL__ < 704
|
||||
, (<>)
|
||||
#endif
|
||||
) where
|
||||
|
||||
import Prelude hiding (writeFile, readFile)
|
||||
import Prelude hiding (writeFile, readFile, head, tail, init, last)
|
||||
import Yesod hiding (Route(..))
|
||||
import Foundation
|
||||
import Data.Monoid (Monoid (mappend, mempty, mconcat))
|
||||
import Control.Applicative ((<$>), (<*>), pure)
|
||||
import Data.Text (Text)
|
||||
import Settings.StaticFiles
|
||||
|
||||
#if __GLASGOW_HASKELL__ < 704
|
||||
infixr 5 <>
|
||||
(<>) :: Monoid m => m -> m -> m
|
||||
(<>) = mappend
|
||||
#endif
|
||||
|
||||
@ -42,12 +42,12 @@ library
|
||||
OverloadedStrings
|
||||
NoImplicitPrelude
|
||||
CPP
|
||||
OverloadedStrings
|
||||
MultiParamTypeClasses
|
||||
TypeFamilies
|
||||
GADTs
|
||||
GeneralizedNewtypeDeriving
|
||||
FlexibleContexts
|
||||
EmptyDataDecls
|
||||
|
||||
executable ~project~
|
||||
if flag(library-only)
|
||||
@ -72,6 +72,7 @@ executable ~project~
|
||||
GADTs
|
||||
GeneralizedNewtypeDeriving
|
||||
FlexibleContexts
|
||||
EmptyDataDecls
|
||||
|
||||
build-depends: base >= 4 && < 5
|
||||
, yesod >= 0.10 && < 0.11
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -31,10 +31,14 @@
|
||||
|
||||
$maybe analytics <- extraAnalytics $ appExtra $ settings master
|
||||
<script>
|
||||
if(!window.location.href.match(/localhost/)){
|
||||
window._gaq = [['_setAccount','#{analytics}'],['_trackPageview'],['_trackPageLoadTime']];
|
||||
YepNope.load({
|
||||
\ load: ('https:' == location.protocol ? '//ssl' : '//www') + '.google-analytics.com/ga.js'
|
||||
});
|
||||
(function() {
|
||||
\ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
\ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
\ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
}
|
||||
\<!-- Prompt IE 6 users to install Chrome Frame. Remove this if you want to support IE 6. chromium.org/developers/how-tos/chrome-frame-getting-started -->
|
||||
\<!--[if lt IE 7 ]>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js">
|
||||
|
||||
@ -98,5 +98,5 @@ instance Yesod ~sitearg~ where
|
||||
-- users receiving stale content.
|
||||
addStaticContent = addStaticContentExternal (const $ Left ()) base64md5 Settings.staticDir (StaticR . flip StaticRoute [])
|
||||
|
||||
-- Enable Javascript async loading
|
||||
yepnopeJs _ = Just $ Right $ StaticR js_modernizr_js
|
||||
-- Place Javascript at bottom of the body tag so the rest of the page loads first
|
||||
jsLoader _ = BottomOfBody
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
name: yesod
|
||||
version: 0.10.1
|
||||
version: 0.10.1.4
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
author: Michael Snoyman <michael@snoyman.com>
|
||||
@ -81,7 +81,7 @@ library
|
||||
, monad-control >= 0.3 && < 0.4
|
||||
, transformers >= 0.2.2 && < 0.3
|
||||
, wai >= 1.1 && < 1.2
|
||||
, wai-extra >= 1.1 && < 1.2
|
||||
, wai-extra >= 1.1 && < 1.3
|
||||
, wai-logger >= 0.1.2
|
||||
, hamlet >= 0.10 && < 0.11
|
||||
, shakespeare-js >= 0.11 && < 0.12
|
||||
@ -101,7 +101,7 @@ executable yesod
|
||||
cpp-options: -DWINDOWS
|
||||
build-depends: parsec >= 2.1 && < 4
|
||||
, text >= 0.11 && < 0.12
|
||||
, shakespeare-text >= 0.10 && < 0.11
|
||||
, shakespeare-text >= 0.10 && < 0.12
|
||||
, bytestring >= 0.9.1.4 && < 0.10
|
||||
, time >= 1.1.4
|
||||
, template-haskell
|
||||
|
||||
Loading…
Reference in New Issue
Block a user