갈루아의 반서재

Widget 이란?

Yesod의 경우 위젯의 역할은 HTML, CSS, Javascript 등의 컴포넌트를 적절히 하나의 HTML로 정리하기 위한 통일된 표현을 부여하기 위한 것입니다. 예를 들면, Web 페이지를 기술하는 실제에서는 아래의 형식적인 관습을 따르는 편이 좋습니다.

  • CSS는 페이지의 head 부분에 기술한다
  • Javascript은 body의 마지막에 기술한다
  • jQuery 등의 외부 파일을 여러번 회독하지 않음
  • 타이틀태그는 한 번 출현

위젯 컴포넌트

컴포넌트의 종류

실제 태그

Yesod에서 취급하기 위한 함수 또는 템플릿 언어
타이틀<title> ... </title>setTitle
외부의 스타일시트<link rel="stylesheet" href="...">addStylesheet계열
외부의 Javascript<script src="..."></script>addScript계열
CSS 코드<style>...</style>Cassius or Lucius
Javascript 코드<script>...</script>Julius
임의의 head 컨텐츠<head>...</head>Hamlet

임의의 body 컨텐츠

<body>...</body>Hamlet

위젯 사용방법

1
2
3
4
5
6
7
8
9
10
# stack new widget yesod-simple && cd widget
Downloading template "yesod-simple" to create project "widget" in widget/ ...
Looking for .cabal or package.yaml files to use to init the project.
Using cabal packages:
- widget/widget.cabal
 
Selecting the best among 12 snapshots...
 
Downloaded lts-10.3 build plan.
AesonException "Error in $.packages.cassava.constraints.flags['bytestring--lt-0_10_4']: Invalid flag name: \"bytestring--lt-0_10_4\""
cs


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
# stack build yesod-bin cabal-install --install-ghc
# stack build
blackbriar-0.0.0: unregistering (components added: exe:blackbriar)
blackbriar-0.0.0: configure (lib + exe)
Configuring blackbriar-0.0.0...
blackbriar-0.0.0: build (lib + exe)
Preprocessing library blackbriar-0.0.0...
[ 1 of 13] Compiling Settings         ( src/Settings.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Settings.o )
[ 2 of 13] Compiling Settings.StaticFiles ( src/Settings/StaticFiles.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Settings/StaticFiles.o )
[ 3 of 13] Compiling Model            ( src/Model.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Model.o )
[ 4 of 13] Compiling Import.NoFoundation ( src/Import/NoFoundation.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Import/NoFoundation.o )
[ 5 of 13] Compiling Foundation       ( src/Foundation.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Foundation.o )
 
src/Foundation.hs:150:5: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for ‘isAuthorized’: Patterns not matched: HaskellR _
[ 6 of 13] Compiling Import           ( src/Import.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Import.o )
[ 7 of 13] Compiling Handler.Comment  ( src/Handler/Comment.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Handler/Comment.o )
[ 8 of 13] Compiling Handler.Common   ( src/Handler/Common.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Handler/Common.o )
[ 9 of 13] Compiling Handler.Echo     ( src/Handler/Echo.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Handler/Echo.o )
[10 of 13] Compiling Handler.Haskell  ( src/Handler/Haskell.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Handler/Haskell.o )
[11 of 13] Compiling Handler.Home     ( src/Handler/Home.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Handler/Home.o )
[12 of 13] Compiling Handler.Profile  ( src/Handler/Profile.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Handler/Profile.o )
[13 of 13] Compiling Application      ( src/Application.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Application.o )
Preprocessing executable 'blackbriar' for blackbriar-0.0.0...
[1 of 1] Compiling Main             ( app/main.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/blackbriar/blackbriar-tmp/Main.o ) [flags changed]
Linking .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/blackbriar/blackbriar ...
blackbriar-0.0.0: copy/register
Installing library in
.stack-work/install/x86_64-linux/lts-9.14/8.0.2/lib/x86_64-linux-ghc-8.0.2/blackbriar-0.0.0-2VBmQYLKFgeLhypfZqR3QO
Installing executable(s) in
.stack-work/install/x86_64-linux/lts-9.14/8.0.2/bin
Registering blackbriar-0.0.0...
cs

다음으로 /widget WidgetR GET 라는 루트에 핸들러를 추가한다.

1
2
3
4
# stack exec -- yesod add-handler
Name of route (without trailing R): Widget
Enter route pattern (ex: /entry/#EntryId): /widget
Enter space-separated list of methods (ex: GET POST): GET
cs


바로 http://localhost:3000/widget 에 접속해보자. 아직까지는 아래 그림에서 보듯이Internal Server Error: 라고 표시가 되지만, 문제는 되지 않는다. 

메시지에 나오는대로 아래와 같이 추가한다.

src/Foundation.hs

1
2
    -- Routes not requiring authentication.
    isAuthorized widgetR _ = return Authorized
cs

그럼 이제 샘플사이트의 레이아웃에 적용하기 위해 아래에서 필요한 파일을 수정해보자. 

사용방법

setTitle 을 통해 html 파일의 타이틀을 지정할 수 있다.

Handler/Widget.hs

1
2
3
4
5
6
7
8
9
{-# LANGUAGE OverloadedStrings #-}
 
module Handler.Widget where
 
import Import
 
getWidgetR :: Handler Html
getWidgetR = defaultLayout $ do
  setTitle "ウィジェットテスト1"
cs

상기 코드가 생성하는 HTML

1
2
3
4
5
6
7
<html>
<head>>
<title>ウィジェットテスト1</title>
</head>
<body>
</body>
</html>
cs

복수의 setTitle 을 기술하면, 아래와 같이 가장 마지막의 ウィジェットテスト3 이 표시된다.

Handler/Widget.hs

1
2
3
4
5
6
7
8
9
10
11
{-# LANGUAGE OverloadedStrings #-}
 
module Handler.Widget where
 
import Import
 
getWidgetR :: Handler Html
getWidgetR = defaultLayout $ do
  setTitle "ウィジェットテスト1"
  setTitle "ウィジェットテスト2"
  setTitle "ウィジェットテスト3"
cs

상기 코드가 생성하는 HTML

1
2
3
4
5
6
7
<html>
<head>>
<title>ウィジェットテスト3</title>
</head>
<body>
</body>
</html>
cs


addStylesheet 계열

스타일시트를 읽어내는 위젯입니다. 아래와 같이 동종의 위젯이 몇 개 제공됩니다. 속성은 [(속성명, 속성값)] 과 같은 형식으로 추가합니다. 

함수명참조처 (로컬)참조처 (리모트)속성정보의 추가
addStylesheetO
addStylesheetAttrsOO
addStylesheetRemoteO
addStylesheetRemoteAttrsOO
addStylesheetEitherOO

사용방법 (로컬 참조)

Handler/Widget.hs

1
2
3
4
5
6
7
8
9
10
11
{-# LANGUAGE OverloadedStrings #-}
 
module Handler.Widget where
 
import Import
 
getWidgetR :: Handler Html
getWidgetR = defaultLayout $ do
  addStylesheet $ StaticR css_bootstrap_css
  addStylesheetAttrs (StaticR css_bootstrap_css) [("title", "Sample")]
  addStylesheet $ StaticR css_bootstrap_css
cs

상기 코드가 생성하는 HTML
1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
<title></title>
 
<link rel="stylesheet" href="http://***.**.***.***:3000/static/css/bootstrap.css?etag=PDMJ7RwX">
<link rel="stylesheet" href="http://***.**.***.***:3000/static/css/bootstrap.css?etag=PDMJ7RwX" title="Sample">
<link rel="stylesheet" href="http://***.**.***.***:3000/static/tmp/autogen-dyDfk8nC.css">
 
</head>
<body>
</body>
</html>
cs


로컬의 정적(static) 파일을 취급하기 위해 아래의 사항을 주의할 필요가 있습니다.

  • static/ 아래에 파일을 배치할 필요가 있음
  • 정적 파일을 패스에 대응하는 안전형URL의 데이터 컨스트럭터는  StaticR 을 사용
  • 참조시의 파일의 패스에 관하여、/ . - 의 기호는 _ 으로 바꾼다.

상기 예에서 StaticR css_bootstrap_css 는 /static/css/bootstrap.css 라고 해석하게 된다.

사용방법(리모트 참조)

CDN을 참조하는 링크의 경우에는 다수의 예를 생각해볼 수 있습니다. 아래는 Bulma 의 css를 가져오는 예제입니다.


Handler/Widget.hs

1
2
3
4
5
6
7
8
9
10
11
{-# LANGUAGE OverloadedStrings #-}
 
module Handler.Widget where
 
import Import
 
getWidgetR :: Handler Html
getWidgetR = defaultLayout $ do
  addStylesheetRemote "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css"
  addStylesheetRemoteAttrs "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css" [("title", "Sample")]
  addStylesheetRemote "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css"
cs

상기 코드가 생성하는 HTML
1
2
3
4
5
6
7
8
9
10
11
<html>
<head>
<title></title>
 
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css" title="Sample">
 
</head>
<body>
</body>
</html>
cs


addScript 계열

스크립트파일을 읽어오기 위한 위젯입니다. addStyleSheet 계열의 함수와 동일합니다.

함수명

참조처 (로컬)

참조처 (리모트)속성정보의 추가
addScriptO
addScriptAttrsOO
addScriptRemoteO
addScriptRemoteAttrsOO
addScriptEitherOO

사용방법은 addStyleSheet 과 동일한 방법으로 할애합니다. 


위젯은 모나드다

위젯은 모나드인 관계로, 작은 위젯을 조합하여 큰 위젯을 만들 수 있다. 

Handler/Widget.hs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{-# LANGUAGE OverloadedStrings #-}
 
module Handler.Widget where
 
import Import
 
getWidgetR :: Handler Html
getWidgetR = defaultLayout $ do
  cssWidget
  jsWidget
  cssWidget
  jsWidget
 
cssWidget :: Widget
cssWidget = do
  addStylesheet $ StaticR css_bootstrap_css
  addStylesheetAttrs (StaticR css_bootstrap_css) [("title", "Sample")]
  addStylesheet $ StaticR css_bootstrap_css
 
jsWidget :: Widget
jsWidget = do
  addStylesheetRemote "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css"
  addStylesheetRemoteAttrs "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css" [("title", "Sample")]
  addStylesheetRemote "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css"
cs


상기 코드가 생성하는 HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
<title></title>
 
<link rel="stylesheet" href="http://***.***.***.***:3000/static/css/bootstrap.css?etag=PDMJ7RwX">
<link rel="stylesheet" href="http://***.***.***.***:3000/static/css/bootstrap.css?etag=PDMJ7RwX" title="Sample">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css">
 
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css" title="Sample">
<link rel="stylesheet" href="http://***.***.***.***:3000/static/tmp/autogen-dyDfk8nC.css">
 
</body>
</html>
cs