まる1日分の周回遅れが発生しているOffice UI Fabric Advent Calendar、第11日目はパネルについて解説します。
OfficeUIのパネル
パネルのサンプルプログラム
Office UI Fabricでダイアログボックスを表示するでも少し触れたように、Office UI Fabric(以降"OfficeUI")では設定画面の表示方法として、ダイアログの他にパネルを使うという方法もありそうです。
設定項目をパネルで設定する簡単なサンプルを作成してみました。以下のような表示になります。パネルもダイアログの表示と同じく、モーダル状態で表示されます(設定項目の値をトグルボタン表示にしてみたところ、ディップスイッチみたいな感じになってしまいました……)。
サンプルソースコードは以下になります。
<!DOCTYPE html>
<html ng-app="App">
<head>
<meta charset="utf-8" />
<title>Panel Sample</title>
<link rel="stylesheet" href="//appsforoffice.microsoft.com/fabric/1.0/fabric.min.css">
<link rel="stylesheet" href="//appsforoffice.microsoft.com/fabric/1.0/fabric.components.min.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="https://rawgit.com/furandon-pig/701ec8a958b4d80c34fb/raw/c3113233b4c8cad3144ee0947d79aed3e3d13c7a/officeui_panel_helper.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
$(document).ready(function() {
if ($.fn.Panel) {
$('.ms-Panel').Panel();
}
// Vanilla JS Components
if (typeof fabric !== "undefined") {
if ('Panel' in fabric) {
var element = document.querySelector('.ms-Panel');
var component = new fabric['Panel'](element);
}
}
});
</script>
</head>
<body ng-controller="AppController">
<div class="ms-Grid-col ms-u-sm6 ms-u-md8 ms-u-lg12">
<button class="ms-Button ms-Button--primary js-togglePanel"> <!-- ボタンを表示する -->
<span class="ms-Button-label">
<i class="ms-Icon ms-Icon--gear" aria-hidden="true"></i>設定
</span>
</button>
</div>
<div class="ms-Grid-col ms-u-sm6 ms-u-md8 ms-u-lg12">
<div class="ms-Grid-col ms-u-sm6">
<div class="ms-Table">
<div class="ms-Table-row">
<span class="ms-Table-cell">設定項目</span>
<span class="ms-Table-cell">設定値</span>
<span class="ms-Table-cell"><br></span>
</div>
<div class="ms-Table-row" ng-repeat="configItem in configItems">
<span class="ms-Table-cell">{{configItem.text}}</span>
<span class="ms-Table-cell">
<label style="color:{{(configItem.value==true)?'crimson':'green'}};">
{{configItem.value}}
</label>
</span>
<span class="ms-Table-cell">
<button class="ms-Button ms-Button--command" ng-click="removeConfig($index)">
<span class="ms-Button-label" style="color:crimson;">
<i class="ms-Icon ms-Icon--trash" aria-hidden="true"></i>削除
</span>
</button>
</span>
</div>
</div> <!-- end of ms-Table -->
<button class="ms-Button ms-Button--command" ng-click="addConfig()">
<span class="ms-Button-label" style="color:green;">
<i class="ms-Icon ms-Icon--plus" aria-hidden="true"></i>追加
</span>
</button>
</div>
</div>
<div class="ms-Panel"> <!-- ここからパネル -->
<div class="ms-Overlay ms-Overlay--dark js-togglePanel"><!-- 空のDIVにする --></div>
<div class="ms-Panel-main">
<div class="ms-Panel-commands">
<div class="ms-CommandBar">
<div class="ms-CommandBar-mainArea">
<div class="ms-CommandBar-sideCommands">
<div class="ms-CommandBarItem">
<div class="ms-CommandBarItem-linkWrapper">
<div class="ms-CommandBarItem-link">
<span class="ms-CommandBarItem-icon ms-Icon ms-Icon--star"></span>
<span class="ms-CommandBarItem-commandText ms-font-m ms-font-weight-regular">設定</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div> <!-- end of ms-Panel-commands -->
<div class="ms-Panel-contentInner">
<span class="ms-Panel-headerText">
<i class="ms-Icon ms-Icon--gear" aria-hidden="true"></i>設定
</span>
<div ng-repeat="configItem in configItems">
<span class="ms-Toggle ms-Toggle--textLeft" style="margin-bottom:8px;"> <!-- トグルボタン -->
<span class="ms-Toggle-description">{{configItem.text}}</span>
<input id="toggle{{$index}}" type="checkbox" class="ms-Toggle-input" ng-model="configItem.value">
<label for="toggle{{$index}}" class="ms-Toggle-field">
<span class="ms-Label ms-Label--off">OFF</span>
<span class="ms-Label ms-Label--on">ON</span>
</label>
</span> <!-- end of ms-Toggle -->
</div>
</div> <!-- end of ms-Panel-contentInner -->
</div> <!-- end of ms-Panel-main -->
</div> <!-- end of ms-Panel -->
<script>
var app = angular.module('App', []);
app.controller('AppController', ['$scope',
function($scope) {
$scope.init = function() {
index = 0;
$scope.configItems = [
{ text: "設定項目(" + (++index) + ")", value: false },
{ text: "設定項目(" + (++index) + ")", value: false },
{ text: "設定項目(" + (++index) + ")", value: false },
];
}
$scope.addConfig = function() {
$scope.configItems.push({ text: "設定項目(" + (++index) + ")", value: false });
}
$scope.removeConfig = function(index) {
$scope.configItems.splice(index, 1);
}
$scope.init();
}
]);
</script>
</body>
</html>
OfficeUIパネルを使用する際の(バッド)ノウハウ
このパネルUIですが、ラジオボタンとドロップダウンリストのケースと同じく、若干のバッドノウハウ(MSのPanelのサンプルを見ただけでは分からない使い方・ハマり所)があります。
モーダル表示は空のDIV要素にする
パネルUIはモーダル状態で表示されます。ということは、モーダル表示用のクラス(ちゃんと確認してないけど、おそらく「ms-Overlay」)でパネルの要素を挟む形になるのかな……?と考えるも、それだと上手く表示されません。
正しく(?)は以下のように、「ms-Overlay」クラスを指定した空のDIV要素を記述してからパネルの中身を記述する形になります。
<div class="ms-Panel"> <!-- ここからパネル -->
<div class="ms-Overlay ms-Overlay--dark js-togglePanel"><!-- 空のDIVにする --></div>
...
パネルUIの初期化
ラジオボタンとドロップダウンリストでは、ページ読み込み時にドロップダウンリストの表示項目を初期化するコードが必要でした。
パネルでも同様に、ページ読み込み時にパネルの初期化を行う必要があります。先のサンプルコードの以下の場所が初期化を行っている箇所です。
$(document).ready(function() {
if ($.fn.Panel) {
$('.ms-Panel').Panel();
}
Panel()の定義は外部のJavaScriptファイルで行っており、筆者のGistに用意したofficeui_panel_helper.jsを読むこむ形になっています(GistからJavaScriptを読み込むにはrawgitを経由するといった別のバッドノウハウも必要になります……)。
<script type="text/javascript" src="https://rawgit.com/furandon-pig/701ec8a958b4d80c34fb/raw/c3113233b4c8cad3144ee0947d79aed3e3d13c7a/officeui_panel_helper.js"></script>
まとめ
まる1日分の周回遅れが発生した第11日目の記事ではパネルUIについて解説しました。ダイアログとパネルを使い分けることで、効果的なUIが作れそうです。