コンテンツ検索 web パーツでホバーパネルを表示してみた

前回のポスト
コンテンツ検索webパーツの表示をカスタマイズする
のオマケです。

SharePoint2013では、検索結果のアイテムにカーソルをあてると詳細がホバーパネルで表示されます。
しかし、コンテンツ検索 web パーツではホバーパネルが表示されません。そこで、なんとか表示させるべくカスタマイズしてみました。

完成イメージはこちら。
20150828
ホバーパネルの表示テンプレートは、マスターページギャラリー>Display Templates>Searchフォルダの中にあります。
このうち、Item_xxx_HoverPanel.htmlというのがそれです。検索結果のファイルタイプによって、表示テンプレートが細かく分けられているのですね。
今回は、Item_Default_HoverPanel.htmlをダウンロードして使います。
ダウンロードしたItem_Default_HoverPanel.htmlを開き、中身を以下のように書き換えます。

書き換えたファイルを「Item_Blog_HoverPanel.html」とリネームして保存し、Searchフォルダにアップロードします。

次に、前回のポストで作成した「Item_BlogPost.html」をダウンロードし、以下のように書き換えます。

書き換えたItem_BlogPost.htmlを、Content Web Partsフォルダにアップロードします。
以上です!
もし、カスタマイズが反映されない場合はコンテンツ検索webパーツの表示テンプレートで「For Blog Post」をえらびなおし、プロパティのマッピングで以下のように選択しなおしてみてください。
20150828-2

なお、カスタマイズにあたってはこちらの記事を参考にしました。
The SharepointWallah: Sharepoint 2013 Search – Adding a hover panel to a content search webpart display template.
C/D/H Talks Tech » Custom Hover Panel on the Content Search Web Part using a Custom Display Template

若干、無理やりな感じもありますが・・・参考になればうれしいです。

コンテンツ検索webパーツの表示をカスタマイズする

だいぶ前になりますが、コンテンツ検索webパーツでブログの新着を表示するやり方を紹介しました。
【2013】コンテンツ検索 webパーツでBlogの新着情報を表示する | Me & SharePoint.

今回の記事と、次回の記事
コンテンツ検索 web パーツでホバーパネルを表示してみた
はその続きとなります。

前回のままではタイトルとサムネイルだけでさびしいので、本文の一部、投稿日、それから「Read More」ボタンを表示してみたいと思います。
完成イメージです。
20150826

これを実現するには、「表示テンプレート」というものをカスタマイズします。
表示テンプレートのカスタマイズについては、MSのサポートチームのブログで詳しく紹介されていますので参考にしてください。
SharePoint 2013 お知らせアイテムを新着順に表示するコンテンツ検索 Web パーツを作成する – Japan SharePoint Support Team Blog – Site Home – TechNet Blogs.
SharePoint 2013 検索結果の表示を制御する表示テンプレート – Japan SharePoint Support Team Blog – Site Home – TechNet Blogs.

さて、マスターページギャラリーからDisplay Templates>Content Web Parts とフォルダをたどって、Item_Picture3Lines.htmlをダウンロードします。
ダウンロードしたテンプレートを「Item_BlogPost.html」とリネームします。
テンプレートを開き、以下のように書き換えます。

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"> 
<head>
<title>For Blog Post</title>

<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>
<mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
<mso:ManagedPropertyMapping msdt:dt="string">'Picture URL'{画像の URL}:'PublishingImage;PictureURL;PictureThumbnailURL','Link URL'{リンクの URL}:'Path','Line 1'{行 1}:'Title','Line 2'{行 2}:'DiscussionPost','Line 3'{行 3}:'Created', 'SecondaryFileExtension','ContentTypeId'</mso:ManagedPropertyMapping>
<mso:MasterPageDescription msdt:dt="string">このアイテム表示テンプレートでは、100 x 100 の大きさでアイテムの画像が左側に表示されます。画像の右側には、タイトル、既定アイテムの説明、カスタムの管理プロパティ用の行が表示されます。</mso:MasterPageDescription>
<mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106603</mso:ContentTypeId>
<mso:TargetControlType msdt:dt="string">;#Content Web Parts;#</mso:TargetControlType>
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
</mso:CustomDocumentProperties>
</xml><![endif]-->
</head>

<body>

    <!--
            Warning: Do not try to add HTML to this section. Only the contents of the first <div>
            inside the <body> tag will be used while executing Display Template code. Any HTML that
            you add to this section will NOT become part of your Display Template.
    -->
    <script>
        $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
    </script>

    <!--
        Use the div below to author your Display Template. Here are some things to keep in mind:
        * Surround any JavaScript logic as shown below using a "pound underscore" (#_ ... _#) token
        inside a comment.

        * Use the values assigned to your variables using an "underscore pound equals"
        (_#= ... =#_) token.
    -->

    <div id="Item_BlogPost">

<!--#_

var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_BlogPost_");

var linkURL = $getItemValue(ctx, "Link URL");
linkURL.overrideValueRenderer($urlHtmlEncodeValueObject);

var line1 = $getItemValue(ctx, "Line 1");
var line2 = $getItemValue(ctx, "Line 2");
var line3 = $getItemValue(ctx, "Line 3");

var StrLine2 = line2.value;
if (StrLine2.length > 150){
    StrLine2 = StrLine2.substr(0, 150) + "...";
}

var pictureURL = $getItemValue(ctx, "Picture URL");
var pictureId = encodedId + "picture";
var pictureMarkup = Srch.ContentBySearch.getPictureMarkup(pictureURL, 100, 100, ctx.CurrentItem, "cbs-picture3LinesImg", line1, pictureId);

line1.overrideValueRenderer($contentLineText);
line2.overrideValueRenderer($contentLineText);
line3.overrideValueRenderer($contentLineText);

var containerId = encodedId + "container";
var pictureLinkId = encodedId + "pictureLink";
var pictureContainerId = encodedId + "pictureContainer";
var dataContainerId = encodedId + "dataContainer";
var line1LinkId = encodedId + "line1Link";
var line1Id = encodedId + "line1";
var line2Id = encodedId + "line2";
var line3Id = encodedId + "line3";

var dataDisplayTemplateTitle = "BlogPost";

 _#-->
        <div class="cbs-picture3LinesContainer" id="_#= containerId =#_" data-displaytemplate="_#= $htmlEncode(dataDisplayTemplateTitle) =#_">
            <div class="cbs-picture3LinesImageContainer" id="_#= pictureContainerId =#_">
<!--#_
if(!linkURL.isEmpty)
{
_#-->
                <a class="cbs-pictureImgLink" href="_#= linkURL =#_" title="_#= $htmlEncode(line1.defaultValueRenderer(line1)) =#_" id="_#= pictureLinkId =#_">
<!--#_
}
_#-->
                    _#= pictureMarkup =#_
<!--#_
if(!linkURL.isEmpty)
{
_#-->
                </a>
<!--#_
}
_#-->
            </div>
            <div class="cbs-picture3LinesDataContainer" id="_#= dataContainerId =#_">
                <a class="cbs-picture3LinesLine1Link" href="_#= linkURL =#_" title="_#= $htmlEncode(line1.defaultValueRenderer(line1)) =#_" id="_#= line1LinkId =#_">
                    <h4 class="cbs-picture3LinesLine1 ms-accentText2 ms-noWrap" id="_#= line1Id =#_"> _#= line1 =#_</h4>
                </a>
<!--#_
if(!line2.isEmpty)
{
_#-->
                <div class="cbs-picture3LinesLine2" style="height:auto;" id="_#= line2Id =#_" > _#= StrLine2 =#_ </div>
<!--#_
}
_#-->
                <div style="overflow:hidden;">
<!--#_
if(!line3.isEmpty)
{
_#--> 
                    <span class="cbs-picture3LinesLine3 ms-textSmall ms-noWrap" id="_#= line3Id =#_" style="float:left;">[Posted : _#= line3 =#_ ]</span>
<!--#_
}
_#-->
                    <a class="cbs-button1" href="_#= linkURL =#_" style="float:right;">Read More</a>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

書き換えたItem_BlogPost.htmlを、ダウンロード元のフォルダにアップロードし、タイトルに「For Blog Post」と入力して保存します。

コンテンツ検索webパーツを設置したページに戻り、webパーツを編集状態にします。
「表示テンプレート」セクションの「アイテム」で、先ほどテンプレートのタイトルに設定した「For Blog Post」を選択します。

20150826-2

もし、うまく内容が反映されない場合は「プロパティのマッピング」でデフォルトで入力されているプロパティを再度選択しなおしてから保存してみてください。

最後に、「Read More」のリンクをボタン状にし、全体の見栄えを整えるためのCSSをページに埋め込みます。
ページを編集状態にし、「スクリプトエディター」を挿入して、コードスニペットのに以下のコードを貼り付けて保存します。

<style>
.cbs-picture3LinesContainer {
    padding: 20px 0;
    margin: 5px;
}
.cbs-picture3LinesImageContainer {
    margin-top: 5px;
}
.cbs-button1{
    text-decoration: none;
    text-align: center;
    display: inline-block;
    background-color: #59b1eb;
    border: 2px solid #59b1eb;
    color: #fff;
    padding: 0 30px;
}
.cbs-button1:visited{
    color: #fff;
}
.cbs-button1:hover {
    background-color: #fff;
    border-color: #59b1eb;
    color: #59b1eb;
    text-decoration: none;
}
.cbs-button1::before,
.cbs-button1::after {
    position: absolute;
    z-index: -1;
    display: block;
    content: '';
}
.cbs-button1,
.cbs-button1::before,
.cbs-button1::after {
    box-sizing: border-box;
    transition: all .3s;
}
</style>

これでOKです!
おなじみのコンテンツクエリwebパーツよりは、xslスタイルシートをいじらなくて済む分カスタマイズのハードルは低いですよね。
これからどんどん使っていきたいと思います!

コンテンツクエリ webパーツでアイテムをダイアログで開く

社内ポータルをSharePointでつくっている場合、コンテンツクエリwebパーツ(cqwp)でサイトコレクション内のお知らせを集約してトップページに表示・・・なんてことはよくやりますよね。

で、cqwpだと、ふつうアイテムのタイトルをクリックすると、同一ウィンドウ内でクリックしたアイテムの表示画面へ遷移していきます。
これを、PCで表示したときはダイアログで開き、モバイルで表示したときは同一画面内で遷移するようにカスタマイズしてみます。
PCでの表示イメージはこんな感じ。
20150708

さて、cqwpのカスタマイズに関しては、Microsoft MVP山崎さん執筆の以下の良記事がありますので、まだコンテンツクエリwebパーツいじったことない・・・という方はまずご一読ください。
若干古い記事ですが、2013となった今でも十分通用する内容で、cqwpをカスタマイズしよう!なんて場面ではもはやバイブルといってよいと思います。
コンテンツ クエリ Web パーツ (1.複数サイトから「お知らせ」を取得する) – SharePoint Technical Notes.
コンテンツ クエリ Web パーツ (2.今日の日付を表示する) – SharePoint Technical Notes.
コンテンツ クエリ Web パーツ (3.更新日時と本文を取得する) – SharePoint Technical Notes.
コンテンツ クエリ Web パーツ (4.本文から不要なタグを削除する) – SharePoint Technical Notes.
コンテンツ クエリ Web パーツ (5.表示部分を整える) – SharePoint Technical Notes.
コンテンツ クエリ Web パーツ (6.リンク機能を修正する) – SharePoint Technical Notes.
コンテンツ クエリ Web パーツ (7.任意の列で並び替える) – SharePoint Technical Notes.
コンテンツ クエリ Web パーツ (8.タスクの一覧を取得する) – SharePoint Technical Notes.

では、上記の記事をひととおり眺めていただいた、という前提で・・・
おもむろにソースコードです。

ItemStyle.xslの、コンテンツクエリwebパーツで使いたいスタイルの「<div class=”link-item”>」のaタグ部分を以下のように書き換えます。

<div class="link-item">
    <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
    <!--<a href="{$SafeLinkUrl}" title="{@LinkToolTip}">-->
    <a onmouseover="javascript:this.style.cursor='pointer';" onclick="OpenModalDialog('{$SafeLinkUrl}','{$DisplayTitle}')"  title="{@LinkToolTip}">
        <xsl:if test="$ItemsHaveStreams = 'True'">
            <xsl:attribute name="onclick">
                <xsl:value-of select="@OnClickForWebRendering"/>
            </xsl:attribute>
        </xsl:if>
        <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">
            <xsl:attribute name="onclick">
                <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
            </xsl:attribute>
        </xsl:if>
        <xsl:value-of select="$DisplayTitle"/>
    </a>
    <div class="description">
        <xsl:value-of select="@Description" />
    </div>
</div>

※ItemStyle.xslを編集したら、忘れずに発行しましょう。

次に、コンテンツクエリwebパーツを配置したページに、スクリプトエディタで以下のJavaScriptを埋め込みます。

<script>
function OpenModalDialog(url, title) {
    if (navigator.userAgent.search(/iPhone/) != -1 || navigator.userAgent.search(/iPad/) != -1 || navigator.userAgent.search(/iPod/) != -1 || navigator.userAgent.search(/Android/) != -1) {
        location.href = url;
        return false;
    }
    var options = { title: title, url: url };
    SP.UI.ModalDialog.showModalDialog(options);
}
</script>

以上でOKです!
検証したのはSharePoint2013ですが、使っている手法は2010のころからあるものばかりなので、2010でも動くと思います。
(2010の場合は、スクリプトを外部ファイルにして、コンテンツエディタwebパーツでページにリンクしてください。)

上で紹介したcqwpのカスタマイズと組み合わせれば、ちょっとcqwpで作ったとは思えないパーツに仕上がりそうですね。

注目リンクをページャを出さずに折り返して全部表示する

SharePoint2013から追加された新しいリスト、「注目リンク」。
いわゆるタイルUIで、SharePoint2013の画面デザインにもしっくりきますし、積極的に使っていきたいアプリではあると思います。

しかしリンクアイテムの数が増えてくると、デフォルトでは画面から見切れてページャが出てきてしまいます。
図1

ページャなしで折り返して全部見せたい!
そういう場合は、以下のCSSをスクリプトエディタ webパーツでページに埋め込みます。

<style>
.ms-promlink-header{
	display: none;
}
.ms-promlink-body {
   	width: 100%;
} 
.ms-tileview-tile-detailsBox{
	background-color: rgba(0,68,112,0.75);
}
</style>

上記サンプルコードでは、画像にオーバーレイするキャプションの背景色も変えてますが、この辺はお好みで。
すると、こんな感じで表示されます。
図2

いかがでしたでしょうか?参考にしていただけるとうれしいです。

対象ユーザーを使って、ビューのアクセス制御っぽいことを実現する

小ネタ、というかメモとして書いておきます。

ご存じのように、SharePointではビューに固有のアクセス権をつけることはできません。
が、ちょっとした工夫でアクセス制御っぽい機能を実現することができます(「ぽい」です、あくまで)。

SharePointのwebパーツには、「対象ユーザー」を設定することができますよね。
リストのビューもwebパーツではあるので、対象ユーザーを設定して特定のユーザーにしか見せないようにできます。

【設定手順】
※以下、画面は2010ですが、2013でも同様にできることを確認しています。

①アクセス制限をかけたいビューを表示した状態で、「サイトの操作」→「ページの編集」を選択します。
②リストビューwebパーツのドロップダウンから、「webパーツの編集」を選択します。
20150114-1
③webパーツの設定画面の「詳細設定」セクションの「対象ユーザー」に、ビューにアクセスさせたいSharePointグループを指定し、「OK」をクリックします。
20150114-2
④リボンで「編集の終了」を押して保存します。
以上です!

これで、指定したグループに登録されていないユーザーは、ページにはアクセスできるもののビューが表示されません。
20150114-3
リボンにも「参照」タブしか表示されず、いい感じです。

厳密にいえば、隠してるだけでほんとのセキュリティではないのですが、こんなやり方もあるよ、ということで。

グルーピングの見出しに色をつけて簡易ダッシュボード的なものをつくってみた

SharePoint2010で、進捗管理にカスタムリストを利用したときのお話です。

サイトのトップページでパッと見て進捗がわかるようにできるといいよね~、というので作ってみたものです。
20140827
リストwebパーツをステータスでグループ化したビューで表示し、グループ化の見出しにJavaScriptで色をつけています。

ソースコードです。

JavaScript : Indicator.js

$(document).ready(function () {
    $("td.ms-gb:contains('Not Started')").css({ "color": "#ffff00", "background-color": "red" });
    $("td.ms-gb:contains('In Progress')").css({ "color": "#0000ff", "background-color": "yellow" });
    $("td.ms-gb:contains('Completed')").css({ "color": "#ffffff", "background-color": "green" });
});

HTML(※こちらをtxtファイルでライブラリに格納し、リストwebパーツを配置したのと同じページにコンテンツエディタwebパーツでリンクします)

<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="/[your site]/Lib/Indicator.js"></script>

こういったwebパーツをいくつかトップページに配置しておけば、簡易ダッシュボード的なものが作れるのではないかと思います。

予定表のフォームで会議ワークスペース列を非表示にする

SharePoint2010の標準の予定表では、イベントのフォームに「ワークスペース」っていう項目がありますよね。
20140708-1

ここにチェックをいれると、このイベントにひもづいた「会議ワークスペース」というサブサイトがサイト内に作成されるわけですが、実務上はサブサイトを作成する権限を一般ユーザーには渡してないケースがままあると思います。

その場合どうなるかというと、会議ワークスペースの作成画面で「OK」ボタンを押すとアクセス拒否画面がばばーんと出ちゃいます。
まあこれで、「あ、これは押したらアカンやつやった・・・」とわかりはするんですけど、できればそんなつれない画面は見せたくない。いや、会議ワークスペースの作成画面自体見せたくない。

というわけで、イベントのフォームで「ワークスペース」列を非表示にするべく、例によってJavaScriptで頑張ってみました。

以下のjsファイルをサイトに保存します。
hideWorkspace.js

$(document).ready(function () {
	$("tr:has(a[name='SPBookmark_WorkspaceLink'])").not("tr:has(tr)").hide(); //DispForm.aspx
	$("tr:has(span[title='Workspace'])').not("tr:has(tr)").hide(); //NewForm.aspx, EditForm.aspx en
	$("tr:has(span[title='ワークスペース'])").not("tr:has(tr)").hide(); //NewForm.aspx, EditForm.aspx jp
});

新規、表示、編集すべてに対応してます。また、ベタな書き方でアレなんですがテンプレートは英日両方いけます。

さて、さらに以下のタグを書いたテキストファイルをサイトに保存します。
LoadJS.txt

<script src="/ファイルへのパス/jquery.min.js" type="text/javascript"></script>
<script src="/ファイルへのパス/hideWorkspace.js" type="text/javascript"></script>

このテキストファイルをコンテンツエディタwebパーツでフォームに埋め込みます。
たとえば、NewForm.aspxに埋め込む場合、リボンの「フォームwebパーツ」のドロップダウンから「既定の新しいフォーム」を選択。
20140708-2

次の画面で「webパーツの追加」のリンクをクリックして、[メディアおよびコンテンツ] カテゴリの「コンテンツエディタ」を選択し、「追加」ボタンをクリック。

追加したコンテンツエディタ webパーツの編集画面で、「コンテンツへのリンク」に先ほどアップしたスクリプトリンクタグを書いたテキストファイルへのパスを指定し、「OK」します。
20140708-3

こんな感じで、編集フォーム、表示フォームにも埋め込んでいけば完了です!
めでたく非表示にすることができました~。

20140708-4