by WebSurfer
2011年2月20日 18:21
jQuery 版の Lightbox plugin を実装してみました。以下の画像はダウンロードしたサンプルに含まれていたもので、サンプルと同様に、次の画像、前の画像を連続して表示できます。
gallery という id を持つ div タグの中に、a タグで囲った img 要素を 5 個並べて表示しています。jQuery のセレクタ $('#gallery a') で gallery の中にある a タグを探し、それに対して lightBox() というスクリプトで href 属性に指定した画像ファイルを Lightbox 中に表示するようにしています。
左の画像は、上の gallery という id を持つ div タグの外にあり、単独で表示される(上の画像と連続して表示されない)ようにしたものです。
a タグで rel="lightbox"(任意で可)として、$('a[rel^=lightbox]') という属性セレクタで rel 要素に lightbox という文字列を含む a タグを探し、それに対して lightBox() というスクリプトで href 属性に指定した画像ファイルを Lightbox 中に表示するようにしています。
BlogEngine.NET へのスクリプトファイルと css ファイルの指定の追加は、以下の Extension を用いました。マスターページに直接書き込む方が簡単ですが、その場合はすべてのテーマのマスターページに書かなければならず、スマートではないので。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using BlogEngine.Core.Web.Controls;
using BlogEngine.Core;
using System.Web.UI.HtmlControls;
[Extension("Enable jQuery Lightbox plugin 0.5",
"1.0",
"<a target=\"_blank\" href=\"http://surferonwww.info/Default.aspx\">WebSurfer</a>")]
public class Lightbox
{
private string extensionName = "LightboxPlugin";
private static string scriptsFolder = "Scripts";
private static string jQueryFilename = "jquery-1.4.1.min.js";
private static string lightboxScriptFilename =
"jquery.lightbox-0.5.pack.js";
private static string stylesFolder = "css";
private static string cssFilename = "jquery.lightbox-0.5.css";
public Lightbox()
{
BlogEngine.Core.Post.Serving +=
new EventHandler<ServingEventArgs>(EnableLightbox);
}
private void EnableLightbox(object sender, ServingEventArgs e)
{
HttpContext context = HttpContext.Current;
if (context.CurrentHandler is System.Web.UI.Page)
{
if (context.Items[extensionName] == null)
{
System.Web.UI.Page page =
(System.Web.UI.Page)context.CurrentHandler;
page.Header.Controls.Add(JavaScriptInclude(scriptsFolder +
"/" + jQueryFilename));
page.Header.Controls.Add(JavaScriptInclude(scriptsFolder +
"/" + lightboxScriptFilename));
HtmlLink lightboxCss = new HtmlLink();
lightboxCss.Attributes["type"] = "text/css";
lightboxCss.Attributes["rel"] = "stylesheet";
lightboxCss.Attributes["href"] =
Utils.RelativeWebRoot + stylesFolder + "/" + cssFilename;
page.Header.Controls.Add(lightboxCss);
context.Items[extensionName] = 1;
}
}
}
#region Private helper methods
private HtmlGenericControl JavaScriptInclude(string url)
{
HtmlGenericControl script = new HtmlGenericControl("script");
script.Attributes["type"] = "text/javascript";
script.Attributes["src"] = ResolveScriptUrl(url);
return script;
}
private string ResolveScriptUrl(string url)
{
return Utils.RelativeWebRoot + "js.axd?path="
+ Utils.RelativeWebRoot + url;
}
#endregion
}
jQuery のスクリプトは、ブログの中に直接書き込んでいます。今回の場合は以下の通りです。なぜかと言えば、今回の例で使った gallery や lightbox という名前を、ブログの記事を書くときに自由に指定したかったからです。
<script type="text/javascript">
//<![CDATA[
$(function () {
$('#gallery a').lightBox({
imageLoading: '/BlogEngine/Images/lightbox-ico-loading.gif',
imageBtnClose: '/BlogEngine/Images/lightbox-btn-close.gif',
imageBtnPrev: '/BlogEngine/Images/lightbox-btn-prev.gif',
imageBtnNext: '/BlogEngine/Images/lightbox-btn-next.gif',
imageBlank: '/BlogEngine/Images/lightbox-blank.gif'
});
$('a[rel^=lightbox]').lightBox({
imageLoading: '/BlogEngine/Images/lightbox-ico-loading.gif',
imageBtnClose: '/BlogEngine/Images/lightbox-btn-close.gif',
imageBtnPrev: '/BlogEngine/Images/lightbox-btn-prev.gif',
imageBtnNext: '/BlogEngine/Images/lightbox-btn-next.gif',
imageBlank: '/BlogEngine/Images/lightbox-blank.gif'
});
});
//]]>
</script>
by WebSurfer
2011年2月5日 16:48
ASP.NET の承認は、"ユーザー" に加えて "ロール" というレベルでの管理をサポートしています。ロール管理では、ユーザーをロールに割り当てることにより、ユーザーのグループを単位として扱うことができます。 詳しくは MSDN ライブラリの ASP.NET のロールによる承認の管理 が参考になると思います。
Forms 認証の場合は、サイト管理者がロールを定義し、ロール情報は SQL Server などのデータベースに格納します。
一方、Windows 認証の場合は Windows アカウントを利用しますので、ロールはそのユーザーが属するグループになります。従って、ロールを定義するのはサーバーの管理者で、ロール情報は Active Directory ドメインコントローラーに格納されるということになります。
当然、Windows 認証の場合もロールによるアクセス制限は可能です。例えば、あるフォルダにロールによるアクセス制限をしておくと、そのロールに属さないユーザーがフォルダ内のページを要求すると下の画像のようなダイアログが出てきます。
ロールによるアクセス制限は、Forms 認証と同様に web.config で定義します。フォルダ直下の web.config に以下のような定義をしておくと、Domain Users グループに属するユーザー以外のアクセスは拒否されます。
<configuration>
<system.web>
<authorization>
<allow roles="<ドメイン名>\Domain Users" />
<deny users="*" />
</authorization>
</system.web>
</configuration>
なお、Windows 認証の場合、web.config でロールを有効にする(web.config で <roleManager enabled="true" /> とする)のは意味がなさそうです。というより、そういう設定はしてはいけないようです。
web.config でロールを有効にすると、Page.User は System.Security.Principal.IPrincipal ではなく、それから派生した System.Web.Security.RolePrincipal になります。そこで WindowsPrincipal オブジェクトを取得するため (WindowsPrincipal)User とすると、"型 'System.Web.Security.RolePrincipal' のオブジェクトを型 'System.Security.Principal.WindowsPrincipal' にキャストできません。" というエラーになりますので。
ここからは先は余談です。
Windows アカウントでは、ユーザーもグループもセキュリティ識別子 (SID) を認識に用いています。よく知られた SID は MSDN ライブラリの Windows サーバー オペレーティング システムの既知のセキュリティ識別子 に一覧がありますので見てください。
SID は S-1-1-0 のように人間にとっては意味不明の文字列ですが、これを Everyone のように ACL エディタで使われている名前に変換する方法を忘れないように書いておきます。
Everyone のような名前は NTAccount オブジェクトから取得できます。NTAccount オブジェクトは IdentityReference.Translate メソッドで取得できます。その例を以下のコードに示します。これを実行すると、上の画像のように表示されます。
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Security.Principal" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
WindowsPrincipal principal = (WindowsPrincipal)User;
// IsInRole("S-1-2-35-545") ではダメ。
if (principal.IsInRole("BUILTIN\\Users"))
{
Label1.Text = "BUILTIN\\Users";
}
WindowsIdentity identity =
(WindowsIdentity)principal.Identity;
SecurityIdentifier sid = identity.Owner;
StringBuilder sb = new StringBuilder();
NTAccount nt = (NTAccount)sid.Translate(typeof(NTAccount));
sb.Append("ユーザーの SID: " + nt.Value +
" (" + sid.ToString() + ")<br /><br />");
sb.Append("ユーザーが属するグループ<br />");
IdentityReferenceCollection irc = identity.Groups;
foreach (IdentityReference ir in irc)
{
NTAccount ntAccount =
(NTAccount)ir.Translate(typeof(NTAccount));
sb.Append(" " + ntAccount.Value +
" (" + ir.Value + ")<br />");
}
Label2.Text = sb.ToString();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
ユーザ: <asp:LoginName ID="LoginName1" runat="server" />
<br />
ロール: <asp:Label ID="Label1" runat="server" />
<hr />
<h1>Windows Users のページ</h1>
<asp:Label ID="Label2" runat="server" />
<hr />
<asp:HyperLink ID="HyperLink1"
runat="server"
NavigateUrl="~/Default.aspx">
入り口に戻る
</asp:HyperLink>
</div>
</form>
</body>
</html>
by WebSurfer
2011年1月23日 15:17
2017/8/16 注記追加
Windows 10 IE11 では Quirks モード(IE5 相当)にしても expression 関数が働かないようで、テーブルのヘッダ・列は固定されませんのでご注意ください。この記事はもう意味がないかもしれませんが、せっかく書いたので残しておきます。
MSDN フォーラムなどで、IE の互換モード(正確には Quirks モードという IE5 以前のレンダリングエンジン)で動く table のヘッダ(tr 要素)を固定する "Freezing" という名前の css に関する質問を時々見かけます。
これは IE 独自拡張の expression 関数を使ったものですが、ListView でヘッダーを 2 行にした場合にも適用できるかどうか試してみました。結果は下の画像のように期待通り表示されました。
ただし、ヘッダーだけでなく列も固定すると、何故か固定した部分の border の幅が広くなってしまい、それを解決する方法が見つかっていないのが悔しいところですが。(汗)
上の画像を作ったコードは以下の通りです。Microsoft が提供している Northwind サンプルデータベースの Products テーブルを使用しています。
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
<%--Quirks モードに設定--%>
<meta http-equiv="X-UA-Compatible" content="IE=5" />
<style type="text/css">
.FreezingHeader
{
z-index: 10;
position: relative;
top: expression(this.offsetParent.scrollTop);
background-color: #0000cc; /* ヘッダ部分の border の色 */
}
.FreezingCol
{
z-index: 1;
left: expression(document.getElementById("freezingDiv").scrollLeft);
position: relative;
background-color: white;
}
#freezingDiv
{
overflow: auto;
width: 400px;
height: 300px;
}
table.style1
{
border-style: none; /* 指定するとスクロールでずれる */
text-align: center;
border-collapse: collapse;
}
table.style1 th
{
border-style: solid;
border-width: 2px;
border-color: #0000cc;
background-color: #6699FF;
color: #FFFFFF;
padding: 5px;
}
table.style1 td
{
border-style: solid;
border-width: 2px;
border-color: #0000cc;
padding: 5px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand=
"SELECT [ProductID], [ProductName], [QuantityPerUnit], [UnitPrice], [UnitsInStock]
FROM [Products]">
</asp:SqlDataSource>
<div id="freezingDiv">
<asp:ListView ID="ListView1"
runat="server"
DataKeyNames="ProductID"
DataSourceID="SqlDataSource1"
EnableModelValidation="True">
<ItemTemplate>
<tr>
<td class="FreezingCol">
<asp:Label ID="ProductIDLabel"
runat="server"
Text='<%# Eval("ProductID") %>' />
</td>
<td class="FreezingCol">
<asp:Label ID="ProductNameLabel"
runat="server"
Text='<%# Eval("ProductName") %>' />
</td>
<td>
<asp:Label ID="QuantityPerUnitLabel"
runat="server"
Text='<%# Eval("QuantityPerUnit") %>' />
</td>
<td>
<asp:Label ID="UnitPriceLabel"
runat="server"
Text='<%# Eval("UnitPrice") %>' />
</td>
<td>
<asp:Label ID="UnitsInStockLabel"
runat="server"
Text='<%# Eval("UnitsInStock") %>' />
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table ID="itemPlaceholderContainer"
runat="server"
class="style1">
<tr runat="server" class="FreezingHeader">
<th runat="server" colspan="2" class="FreezingCol">
ID and Name</th>
<th runat="server" colspan="3">
Details of Products</th>
</tr>
<tr runat="server" class="FreezingHeader">
<th runat="server" class="FreezingCol">
ProductID</th>
<th runat="server" class="FreezingCol">
ProductName</th>
<th runat="server">
QuantityPerUnit</th>
<th runat="server">
UnitPrice</th>
<th runat="server">
UnitsInStock</th>
</tr>
<tr ID="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
個人的には IE 専用のハック的な方法と思っていますので、これを実際に使うことはなさそうですが、こういったこともできるということでご参考まで。
------------ 2011/4/29 追記 ------------
上の画像のように固定した部分の border の幅が広くなってしまう問題は、以下のように、class="FreezingCol" を付与した th, td 要素に inline スタイルで border の幅を指定してやることで解決できます。
・・・前略・・・
<ItemTemplate>
<tr>
<td class="FreezingCol" style="border-width: 1 1 1 2;">
<asp:Label ID="ProductIDLabel"
runat="server"
Text='<%# Eval("ProductID") %>' />
</td>
<td class="FreezingCol" style="border-width: 1 1 1 1;">
<asp:Label ID="ProductNameLabel"
runat="server"
Text='<%# Eval("ProductName") %>' />
</td>
・・・中略・・・
</ItemTemplate>
<LayoutTemplate>
<table ID="itemPlaceholderContainer"
runat="server"
class="style1">
<tr runat="server" class="FreezingHeader">
<th runat="server" colspan="2" class="FreezingCol" style="border-width: 2 1 1 2;">
ID and Name</th>
<th runat="server" colspan="3">
Details of Products</th>
</tr>
<tr runat="server" class="FreezingHeader">
<th runat="server" class="FreezingCol" style="border-width: 1 1 1 2;">
ProductID</th>
<th runat="server" class="FreezingCol" style="border-width: 1 1 1 1;">
ProductName</th>
・・・後略・・・