今回は、大企業向けグループウェア「サイボウズGaroon」のポータル活用企画として、「行き先案内板」を作成していきたいと思います。
自由に必要な情報を配置できる「HTMLポートレット」ですが、配置しているリンクが年度ごとに変わったりする場合htmlを直接編集する手動のメンテナンスが発生します。
担当者が気付かずに放置してしまい、しまいには使われないゾンビポータルと化す前に、サクッと情報を更新できるポートレットを今回は作っていきます。
HTMLポートレット
固定リンクがコピーされました
バックエンドで使うのは…そう、kintoneです。
kintoneでリソースを管理することで、Garoonのシステム管理権限をもっていなくても配置するリソースを変えることができます。
つまり、ポータルで発信したい情報を担当部署の担当者の作業だけで変更でき、メンテナンスのコストを下げることができます。
それではkintoneに表示するリソースを保管して、Garoonのポートレットに表示させる小技を披露していきたいと思います。
ポートレットに動的に表示するコンテンツは、kintone側でレコードとして保存して使いますが、今回作成するサンプルでは、各パーツで表示する画像ファイルがいくつかあります。
今回画像ファイルの置き場として、Garoonの「ファイル管理」にファイルを保存して使っていきたいと思います。
では、ファイル管理を使ってリソースの準備をしていきたいと思います。
- 今回使う画像ファイル類は以下のzipファイルよりダウンロードしてください。
garoon-portal1.zip
- 分かりやすくするため、ファイル管理にポートレット用のフォルダーを作成します。今回は「kinポータル用画像」とします。
- ページのヘッダー用画像、各boxの吹き出し用画像、各boxのフッター用画像、ページのフッター用画像を「kinポータル用画像」に保存します。
CSSファイルの準備
固定リンクがコピーされました
次にレイアウト調整用ファイル「main.css」を作成します。
-
CSSサンプルコード
を参考に、「main.css」を作成してください。
文字コードは「UTF-8」で保存します。
- ファイル管理の一覧画面で、さきほど保存した以下のファイルのダウンロードアイコンから画像のアドレス情報をひとつずつコピーします。
- 「bg_header.png」
- 「bg_box_footer.png」
- 「bg_lead_red.png」
- 「bg_lead_yellow.png」
- 「bg_lead_green.png」
- 「bg_lead_purple.png」
- 「bg_lead_turquoise.png」
- 「bg_lead_blue.png」
- 「main.css」の
/*画像パスの変更*/
部分のXXXを含むリンクをコピーしたリンク(「/g」以降の部分)で書き換えます。
CSSサンプルコード
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
|
/*
* Garoon Portal sample program
* Copyright (c) 2016 Cybozu
*
* Licensed under the MIT License
* https://opensource.org/license/mit/
*/
@charset "UTF-8";
/*
*
* Title: Calomama Graph
* Last Modified: 2015-05-19
* Description: Pages Style
*
*/
/* =========== INDEX LIST ============
1: RESET
2: COMMON
3: LAYOUT
4: MODULE
====================================== */
/* ===================================
1: RESET
====================================== */
/*@import "normalize";*/
/* ===================================
2: COMMON
====================================== */
.template-portal01 h1, .template-portal01 h2, .template-portal01 h3, .template-portal01 h4, .template-portal01 h5, .template-portal01 h6 {
margin: 0;
font-weight: normal;
line-height: 1.5;
}
.template-portal01 p,
.template-portal01 ul,
.template-portal01 ol,
.template-portal01 dl {
list-style: none;
margin: 0;
line-height: 1.4;
font-size: 11px;
font-size: 1.1rem;
}
.template-portal01 img {
line-height: 1;
vertical-align: top;
}
.template-portal01 table {
width: 100%;
border-collapse: collapse;
}
.template-portal01 th,
.template-portal01 td {
text-align: left;
}
/* ===================================
4: MODULE
====================================== */
.template-portal01 {
background: #f2f2f2;
font-size: 12px;
font-size: 1.2rem;
}
.template-portal01-header {
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_header.png?hid=XXX&fid=XXX&ticket=&.png) repeat top left;
margin-bottom: 20px;
padding: 35px 10px 29px;
text-align: center;
}
.template-portal01-header h1 {
font-size: 30px;
font-size: 3rem;
font-weight: bold;
color: #fff;
text-shadow: 0px 2px 0px rgba(0, 0, 0, 0.2);
}
.template-portal01-header .lead {
font-size: 14px;
font-size: 1.4rem;
color: #fff;
}
.template-portal01-footer {
background: #666;
padding: 30px;
color: #fff;
}
.template-portal01-footer p {
font-size: 9px;
font-size: 0.9rem;
}
.template-portal01-footer .footer-nav-wrap {
display: table;
width: 100%;
}
.template-portal01-footer .footer-nav-wrap .nav-box {
width: 33.33333333%;
display: table-cell;
box-sizing: border-box;
padding: 20px 20px 0 0;
}
.template-portal01-footer .footer-nav-wrap .nav-box li {
margin-bottom: 7px;
}
.template-portal01-footer .footer-nav-wrap .nav-box a {
display: inline-block;
padding-left: 15px;
color: #fff;
font-size: 9px;
font-size: 0.9rem;
}
.template-portal01-footer .footer-nav-wrap .nav-box a:before {
content: "";
display: inline-block;
width: 0;
height: 0;
border-style: solid;
border-width: 4px 0 4px 6px;
border-color: transparent transparent transparent #ffffff;
margin-right: 5px;
margin-left: -15px;
}
.template-portal01-footer .footer-nav-wrap .nav-box a:hover {
color: #ffff66;
}
.template-portal01-contents {
padding: 0 10px;
}
.template-portal01-contents:after {
content: '';
display: block;
clear: both;
}
.template-portal01-box {
width: 33.333333%;
margin-bottom: 20px;
float: left;
}
.template-portal01-box > a {
display: block;
text-decoration: none;
color: #fff;
}
.template-portal01-box > a:hover {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=$trans*100)";
filter: alpha(opacity=80);
-moz-opacity: 0.8;
-khtml-opacity: 0.8;
opacity: 0.8;
}
.template-portal01-box .box-wrap {
padding-left: 20px;
}
.template-portal01-box .box-wrap > div {
background: #999;
}
.template-portal01-box .box-wrap .box-header {
padding: 15px 10px 0;
}
.template-portal01-box .box-wrap .box-header:after {
content: '';
display: block;
clear: both;
}
.template-portal01-box .box-wrap .box-header .lead {
width: 120px;
height: 78px;
box-sizing: border-box;
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_lead_red.png?hid=XXX&fid=XXX&ticket=&.png) no-repeat top left;
-moz-background-size: 120px 78px;
-webkit-background-size: 120px 78px;
-o-background-size: 120px 78px;
background-size: 120px 78px;
padding: 20px 23px;
margin-top: -25px;
margin-left: -20px;
margin-right: 10px;
line-height: 1.2;
color: #666;
float: left;
font-size: 9px;
font-size: 0.9rem;
}
.template-portal01-box .box-wrap .box-header h2 {
margin-bottom: 15px;
font-size: 25px;
font-size: 2.5rem;
text-shadow: 0px 2px 0px rgba(0, 0, 0, 0.2);
line-height: 1;
white-space: nowrap;
font-weight: bold;
color: #fff;
}
.template-portal01-box .box-wrap .box-content {
display: table;
width: 100%;
}
.template-portal01-box .box-wrap .box-content > div {
display: table-cell;
padding: 5px 20px 20px;
vertical-align: top;
}
.template-portal01-box .box-wrap .box-content .content-text {
padding-left: 0px;
color: #fff;
text-shadow: 0px 2px 0px rgba(0, 0, 0, 0.2);
}
.template-portal01-box .box-wrap .box-footer {
padding: 10px;
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_box_footer.png?hid=XXX&fid=XXX&ticket=&.png);
position: relative;
}
.template-portal01-box .box-wrap .box-footer:after {
content: "";
display: block;
position: absolute;
right: 0;
bottom: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 0 0 25px 25px;
border-color: transparent transparent #f2f2f2 transparent;
}
.template-portal01-box .box-wrap .box-red {
background: #ff6666;
}
.template-portal01-box .box-wrap .box-red .box-header .lead {
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_lead_red.png?hid=XXX&fid=XXX&ticket=&.png) no-repeat top left;
-moz-background-size: 120px 78px;
-webkit-background-size: 120px 78px;
-o-background-size: 120px 78px;
background-size: 120px 78px;
}
.template-portal01-box .box-wrap .box-yellow {
background: #ebb218;
}
.template-portal01-box .box-wrap .box-yellow .box-header .lead {
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_lead_yellow.png?hid=XXX&fid=XXX&ticket=&.png) no-repeat top left;
-moz-background-size: 120px 78px;
-webkit-background-size: 120px 78px;
-o-background-size: 120px 78px;
background-size: 120px 78px;
}
.template-portal01-box .box-wrap .box-green {
background: #91cd5c;
}
.template-portal01-box .box-wrap .box-green .box-header .lead {
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_lead_green.png?hid=XXX&fid=XXX&ticket=&.png) no-repeat top left;
-moz-background-size: 120px 78px;
-webkit-background-size: 120px 78px;
-o-background-size: 120px 78px;
background-size: 120px 78px;
}
.template-portal01-box .box-wrap .box-purple {
background: #c684ca;
}
.template-portal01-box .box-wrap .box-purple .box-header .lead {
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_lead_purple.png?hid=XXX&fid=XXX&ticket=&.png) no-repeat top left;
-moz-background-size: 120px 78px;
-webkit-background-size: 120px 78px;
-o-background-size: 120px 78px;
background-size: 120px 78px;
}
.template-portal01-box .box-wrap .box-blue {
background: #61aee4;
}
.template-portal01-box .box-wrap .box-blue .box-header .lead {
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_lead_blue.png?hid=XXX&fid=XXX&ticket=&.png) no-repeat top left;
-moz-background-size: 120px 78px;
-webkit-background-size: 120px 78px;
-o-background-size: 120px 78px;
background-size: 120px 78px;
}
.template-portal01-box .box-wrap .box-turquoise {
background: #25d3c4;
}
.template-portal01-box .box-wrap .box-turquoise .box-header .lead {
/* 画像パスの変更 */
background: url(/g/cabinet/download.csp/-/bg_lead_turquoise.png?hid=XXX&fid=XXX&ticket=&.png) no-repeat top left;
-moz-background-size: 120px 78px;
-webkit-background-size: 120px 78px;
-o-background-size: 120px 78px;
background-size: 120px 78px;
}
.template-portal01 .btn-text {
text-align: center;
font-size: 9px;
font-size: 0.9rem;
}
.template-portal01 .btn-text:after {
content: "";
display: inline-block;
width: 0;
height: 0;
margin-left: 5px;
border-style: solid;
border-width: 5px 0 5px 10px;
border-color: transparent transparent transparent #ffffff;
}
|
JavaScriptファイル
固定リンクがコピーされました
最後にkintoneとの連携用のJavaScriptファイル「kinGrIntegration.js」を作成します。
JavaScriptサンプルコード
を参考に、「kinGrIntegration.js」を作成します。
文字コードは「UTF-8」でファイル管理に保存します。
JavaScriptサンプルコード
の以下の項目は環境に応じて書き換えてください。
JavaScriptサンプルコード
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
106
107
108
109
110
111
112
|
/*
* Garoon Portal sample program
* Copyright (c) 2016 Cybozu
*
* Licensed under the MIT License
* https://opensource.org/license/mit/
*/
(()=> {
'use strict';
const APP_ID = 101;
const REC_ID = 1;
let count = 0;
fetch(`/k/v1/record.json?app=${APP_ID}&id=${REC_ID}`, {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
}
})
.then(response => response.json())
.then(resp => {
const record = resp.record;
const fileKeyArray = [];
const mainTitle = escapeHtml(record.gr_title.value);
const subTitle = escapeHtml(record.sub_title.value);
document.getElementById('main_title').innerHTML = mainTitle;
document.getElementById('main_title_sub').innerHTML = subTitle;
if (record.S_TABLE.value) {
const divComment = document.getElementById('comment');
for (let i = 0; i < record.S_TABLE.value.length; i++) {
const tableObj = record.S_TABLE.value[i].value;
if (tableObj.img.value.length > 0) {
fileKeyArray.push(tableObj.img.value[0].fileKey);
}
const color = escapeHtml(tableObj.color.value);
const comment = escapeHtml(tableObj.comment.value);
const title = escapeHtml(tableObj.title.value);
const titleSub = escapeHtml(tableObj.title_sub.value);
const footer = escapeHtml(tableObj.footer.value);
const link = escapeHtml(tableObj.link.value);
const parentDiv = document.createElement('div');
parentDiv.classList.add('template-portal01-box');
const linkDiv = document.createElement('a');
linkDiv.href = link;
const wrapDiv = document.createElement('div');
wrapDiv.classList.add('box-wrap');
const colorDiv = document.createElement('div');
colorDiv.classList.add(color);
const headerDiv = document.createElement('div');
headerDiv.classList.add('box-header');
headerDiv.innerHTML = `<p class="lead">${comment}</p><h2>${title}</h2>`;
colorDiv.appendChild(headerDiv);
const boxContentDiv = document.createElement('div');
boxContentDiv.classList.add('box-content');
const contentIconDiv = document.createElement('div');
contentIconDiv.classList.add('content-icon');
const img = document.createElement('img');
img.id = 'capture_' + i;
img.width = 55;
img.height = 55;
contentIconDiv.appendChild(img);
boxContentDiv.appendChild(contentIconDiv);
const contentTextDiv = document.createElement('div');
contentTextDiv.classList.add('content-text');
contentTextDiv.innerHTML = `<p>${titleSub}</p>`;
boxContentDiv.appendChild(contentTextDiv);
colorDiv.appendChild(boxContentDiv);
const footerDiv = document.createElement('div');
footerDiv.classList.add('box-footer');
footerDiv.innerHTML = `<p class="btn-text">${footer}</p>`;
colorDiv.appendChild(footerDiv);
wrapDiv.appendChild(colorDiv);
linkDiv.appendChild(wrapDiv);
parentDiv.appendChild(linkDiv);
divComment.appendChild(parentDiv);
}
}
if (fileKeyArray.length > 0) {
loopFetchFile(fileKeyArray[count]);
}
function loopFetchFile(key) {
fetch(`/k/v1/file.json?fileKey=${key}`, {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
}
})
.then(response => response.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
document.getElementById('capture_' + count).src = url;
if (count < fileKeyArray.length - 1) {
count++;
loopFetchFile(fileKeyArray[count]);
}
});
}
});
const escapeHtml = (str) => {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
})();
|
Garoonポートレットの準備
固定リンクがコピーされました
ポートレットのHTML
固定リンクがコピーされました
今回使うポートレットを作成していきます。
下記は、ヘッダー部分、kintoneからのデータ表示部分とフッター部分を作成するポートレットです。
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
|
<!--
* Garoon Portal sample program
* Copyright (c) 2016 Cybozu
*
* Licensed under the MIT License
* https://opensource.org/license/mit/
-->
<div class="template-portal01">
<header class="template-portal01-header">
<h1 id='main_title'></h1>
<p id='main_title_sub' class="lead"></p>
</header>
<div class='template-portal01-contents'>
<div id='comment'>
<!-- ここにkintoneから取得したデータが表示されます。 -->
</div>
</div>
<footer class="template-portal01-footer">
<p>必要な書類をダウンロードできます。</p>
<div class="footer-nav-wrap">
<ul class="nav-box">
<li><a href="#">席次表</a></li>
<li><a href="#">組織図</a></li>
</ul>
<ul class="nav-box">
<li><a href="#">システムマニュアル</a></li>
<li><a href="#">確定申告用紙</a></li>
</ul>
<ul class="nav-box">
<li><a href="#">オフィス利用マニュアル</a></li>
<li><a href="#">名刺発注マニュアル</a></li>
</ul>
</div>
</footer>
</div><!--//.template-portal01-->
|
JavaScriptファイルとCSSファイルのアップロード
固定リンクがコピーされました
JavaScript / CSSによるカスタマイズから「kinGrIntegration.js」と「main.css」をアップロードします。
ポートレットを作成したら、ポータルに配置しましょう。
ポータルに配置したら公開設定を行います。
kintoneアプリの準備
固定リンクがコピーされました
リソース保管用アプリの作成
固定リンクがコピーされました
Garoonのポータルに表示させるためのリソース保管用アプリを作成します。
kintoneアプリのフィールドは以下のように配置します。
リソース用のフィールドはすべてテーブル化していきます。
フィールドタイプ |
フィールド名 |
フィールドコード |
備考 |
文字列(1行) |
ポートレット名 |
port_name |
任意(配置しなくても連携に影響しません) |
文字列(1行) |
タイトル |
gr_title |
|
文字列(1行) |
サブタイトル |
sub_title |
|
テーブル |
ポートレット用リソース |
S_TABLE |
以下のフィールドをテーブルに含める- 色
- 吹き出し
- パーツタイトル
- パーツフッター
- パーツサブタイトル
- リンク
- 画像
|
ドロップダウン |
色 |
color |
S_TABLEに含める 項目と順番
- box-red
- box-yellow
- box-green
- box-purple
- box-blue
- box-turquoise
|
文字列(1行) |
吹き出し |
comment |
S_TABLEに含める |
文字列(1行) |
パーツタイトル |
title |
S_TABLEに含める |
文字列(1行) |
パーツフッター |
footer |
S_TABLEに含める |
文字列(複数行) |
パーツサブタイトル |
title_sub |
S_TABLEに含める |
リンク |
リンク |
link |
S_TABLEに含める 入力値の種類:Webサイトのアドレス |
添付ファイル |
画像 |
img |
S_TABLEに含める |
作成したアプリのキャプチャ
kintoneにレコードを登録します。
作成したGaroonポータルにkintoneで登録した情報が表示されたら成功です!
今回のGaroonポートレット活用はいかがでしょうか?ぜひ、自社の環境で使えるかトライしてみてください。
まだまだ活用できるシーンがありそうなので、今後もTipsを定期的に公開していきたいと思います。
ガルーンポータル活用Tips
- 2020/02/19
jQueryの追加手順およびjQuery.noConflict(true)
を使うようにコードを修正
- 2024/03/25
- jQueryを使わないようにコードを修正
- JavaScriptとCSSファイルをファイル管理にアップロードする方法から、ポータルの「JavaScript / CSSによるカスタマイズ」を使用する方法に変更