WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

Lightbox Plugin

by WebSurfer 20. February 2011 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>

Tags: ,

BlogEngine.NET

ModalPopup で編集・更新操作

by WebSurfer 14. October 2010 23:18

DB の更新などで、まず一覧画面にレコード一覧を表示してユーザーに選択させ、一覧画面は開いたまま別に編集画面を開いてそこでレコードを編集してもらい、編集画面の[更新]ボタンクリックで DB を更新すると共に編集画面は閉じて、更新結果を一覧画面に反映したいといった要求を時々聞きます。

1 ページで行うか、2 ページ使う場合は一覧画面 → 編集画面 → 一覧画面と遷移していけば難しくありませんが、上記のように開いたままの一覧画面に、編集画面による更新結果を反映するのは難しいです(というよりほとんど無理と思います)。

という訳で、実際は 1 ページで行って、見かけは 2 画面で行うようにする方法を紹介します。

2 画面で選択・編集・更新操作

具体的にどうするかというと、一覧を表示する GridView と、レコードの編集を行う DetailsView を 1 ページに配置し、DetailsView を ASP.NET AJAX Control Toolkit の ModalPopup で表示するというものです。

GridView の各行に配置した[編集]ボタンをクリックすると、ModalPopup の中の DetailsView が表示され、当該行のレコードを編集できます。その間、バックグラウンドは暗く表示され、GridView の操作はできません。

DetailsView の編集が終わったら、[更新]ボタン(上の画像、下のコードでは[Save]ボタン)をクリックすると DB の当該レコードが更新され、ModalPopup が非表示になります。

そして GridView 上で更新された行がハイライトされます。(以下のコードでは、バックグラウンドが黄色に変わり、6 秒間で3 回点滅した後、元のスタイルに戻ります)。

コードは以下のとおりです。Microsoft 提供のサンプルデータベース Northwind の Customers テーブルを使用しています。

なお、Opera 10.63 では[Save]ボタンをクリックしたとき ModalPopup が消えないという問題があります。IE8, Firefox 3.6.10, Safari 5.0.2 は問題なしでした。

<%@ Page Language="C#" %>
<%@ Register Assembly="AjaxControlToolkit"
  Namespace="AjaxControlToolkit" 
  TagPrefix="asp" %>

<!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 GridView1_SelectedIndexChanged(object sender, EventArgs e)
  {
    DetailsView1.DefaultMode = DetailsViewMode.Edit;
    UpdatePanel2.Update();
    ModalPopupExtender1.Show();
  }

  protected void  LinkButton1_Click(object sender, EventArgs e)
  {
    DetailsView1.UpdateItem(false);
    GridView1.DataBind();
    UpdatePanel1.Update();
    ModalPopupExtender1.Hide();

    if (ScriptManager.GetCurrent(this).IsInAsyncPostBack)
    {
      ScriptManager.GetCurrent(this).RegisterDataItem(GridView1, 
        GridView1.SelectedIndex.ToString());
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
  <style type="text/css">
    /*Modal Popup*/
    .modalBackground {
      background-color: Gray;
      filter: alpha(opacity=70);
      opacity: 0.7;
    }

    tr.updated td {
      background-color: yellow;
    }

    .detail {
      background-color: #ffffff;
    }
  </style>
</head>
<body>
  <form id="form1" runat="server">
  <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
  </asp:ToolkitScriptManager>
  <script type="text/javascript">
  <!--
    Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(pageLoaded);

    function pageLoaded(sender, args) {
      var updateRowIndex = args.get_dataItems()["GridView1"];
      if (updateRowIndex) {
        var tr = $get("GridView1").rows[parseInt(updateRowIndex) + 1];
        $(tr).addClass('updated').children('td')
          .fadeTo(1000, 0.33).fadeTo(1000, 1.0)
          .fadeTo(1000, 0.33).fadeTo(1000, 1.0)
          .fadeTo(1000, 0.33).fadeTo(1000, 1.0);
        window.setTimeout(function () {
          $(tr).removeClass('updated');
        }, 6000);
      }
    }
  //-->
  </script>
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT [CustomerID], [CompanyName], [ContactName], 
          [ContactTitle], [Phone] 
        FROM [Customers]">
    </asp:SqlDataSource>
    <asp:UpdatePanel ID="UpdatePanel1" 
      runat="server" 
      UpdateMode="Conditional">
      <ContentTemplate>
        <asp:GridView ID="GridView1" 
          runat="server" 
          AutoGenerateColumns="False" 
          DataKeyNames="CustomerID" 
          DataSourceID="SqlDataSource1" 
          EnableModelValidation="True" 
          OnSelectedIndexChanged="GridView1_SelectedIndexChanged" 
          AllowPaging="True">
          <Columns>
            <asp:BoundField DataField="CustomerID" 
              HeaderText="CustomerID" 
              ReadOnly="True" 
              SortExpression="CustomerID" />
            <asp:BoundField DataField="CompanyName" 
              HeaderText="CompanyName" 
              SortExpression="CompanyName" />
            <asp:BoundField DataField="ContactName" 
              HeaderText="ContactName" 
              SortExpression="ContactName" />
            <asp:BoundField DataField="ContactTitle" 
              HeaderText="ContactTitle" 
              SortExpression="ContactTitle" />
            <asp:BoundField DataField="Phone" 
              HeaderText="Phone" 
              SortExpression="Phone" />
            <asp:CommandField SelectText="編集" 
              ShowSelectButton="True" />
          </Columns>
        </asp:GridView>
      </ContentTemplate>
    </asp:UpdatePanel>
  </div>
  <div>
    <asp:SqlDataSource ID="SqlDataSource2" runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand=
        "SELECT [CustomerID], [CompanyName], [ContactName], 
           [ContactTitle], [Phone] 
        FROM [Customers] 
        WHERE ([CustomerID] = @CustomerID)" 
      UpdateCommand=
        "UPDATE [Customers] 
        SET [CompanyName]=@CompanyName, [ContactName]=@ContactName, 
          [ContactTitle]=@ContactTitle, [Phone]=@Phone 
        WHERE [CustomerID] = @CustomerID">
      <SelectParameters>
        <asp:ControlParameter ControlID="GridView1" Name="CustomerID" 
          PropertyName="SelectedValue" Type="String" />
      </SelectParameters>
      <UpdateParameters>
        <asp:Parameter Name="CompanyName" Type="String" />
        <asp:Parameter Name="ContactName" Type="String" />
        <asp:Parameter Name="ContactTitle" Type="String" />
        <asp:Parameter Name="Phone" Type="String" />
        <asp:Parameter Name="CustomerID" Type="String" />
      </UpdateParameters>
    </asp:SqlDataSource>
    <asp:Panel ID="Panel1" runat="server" CssClass="detail">
      <asp:UpdatePanel ID="UpdatePanel2" 
        runat="server" 
        UpdateMode="Conditional">
        <ContentTemplate>
          <asp:Button ID="DummyButton" 
            runat="server" 
            style="display: none;" />
          <asp:DetailsView ID="DetailsView1" 
            runat="server" 
            AutoGenerateRows="False" 
            DataKeyNames="CustomerID" 
            DataSourceID="SqlDataSource2" 
            EnableModelValidation="True">
            <Fields>
              <asp:BoundField DataField="CustomerID" 
                HeaderText="CustomerID" 
                ReadOnly="True" 
                SortExpression="CustomerID" />
              <asp:BoundField DataField="CompanyName" 
                HeaderText="CompanyName" 
                SortExpression="CompanyName" />
              <asp:BoundField DataField="ContactName" 
                HeaderText="ContactName" 
                SortExpression="ContactName" />
              <asp:BoundField DataField="ContactTitle" 
                HeaderText="ContactTitle" 
                SortExpression="ContactTitle" />
              <asp:BoundField DataField="Phone" 
                HeaderText="Phone" 
                SortExpression="Phone" />
            </Fields>
          </asp:DetailsView>
          <div>
            <asp:LinkButton ID="LinkButton1" 
              runat="server" 
              onclick="LinkButton1_Click" 
              Text="Save" />
            <asp:LinkButton ID="LinkButton2" 
              runat="server" 
              CausesValidation="False" 
              Text="Cancel" />
          </div>
          <asp:ModalPopupExtender ID="ModalPopupExtender1" 
            runat="server" 
            PopupControlID="Panel1" 
            TargetControlID="DummyButton" 
            CancelControlID="LinkButton2" 
            BackgroundCssClass="modalBackground">
          </asp:ModalPopupExtender>
        </ContentTemplate>
      </asp:UpdatePanel> 
    </asp:Panel> 
  </div>
  </form>
</body>
</html>

ネタは先の記事 jQuery の本を買いました で紹介した本のサンプルです(サンプルそのままではなく、不要な部分の削除、誤りの修正を行っています)。

jQuery の本なのに、jQuery を使っているのは GridView 上で更新された行がハイライトされるところだけです。もっと使えるのかと思っていたのですが、更新操作のサーバーとの連携が難しいようで、ちょっと期待はずれでした。

---------------- 2011/5/29 追記 ----------------

Opera では[Save]ボタンをクリックしたとき ModalPopup が消えないという問題があると書きましたが、UpdatePanel で囲うのを GridView と DetailsView に分けず一つにまとめるとその問題が回避できます。

その場合、GridView1_SelectedIndexChanged メソッドの UpdatePanel2.Update(); および LinkButton1_Click メソッドの UpdatePanel1.Update(); は不要です。

Tags: , , ,

AJAX

GridView 内の全 CheckBox をオン(jQuery)

by WebSurfer 8. October 2010 22:11

GirdView の各行に配置した複数の CheckBox に、一度に全部チェックを入れたり外したりする操作を、クライアントサイドのスクリプトで実行する方法の jQuery バージョンです。

普通の JavaScript を使ったバージョンは、先の記事 GridView 内の全 CheckBox をオン にありますので、見比べてみてください。

ネタは先の記事 jQuery の本を買いました で紹介した本の中のサンプルです。

コードは以下の通りです。説明はコードの中にコメントとして入れましたので、そちらを参照してください。

jQuery を使うと、普通の JavaScript を使った場合と比べて、かなりコード量を減らすことができるのは確かのようです。でも、考え方がかなり違うようで、コードの書き方も自分の常識を超えてました。jQuery のセレクタのパワーを垣間見ることができたような気もしますが、正直言って、まだよく分かってないです。(笑)

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  DataTable CreateDataTable()
  {
    DataTable dt = new DataTable();
    DataRow dr;

    dt.Columns.Add(new DataColumn("Item", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Name", typeof(string)));
    dt.Columns.Add(new DataColumn("Price", typeof(Int32)));

    for (int i = 0; i < 10; i++)
    {
      dr = dt.NewRow();
      dr["Item"] = i;
      dr["Name"] = "Item " + i.ToString();
      dr["Price"] = 123000 * (i + 1);
      dt.Rows.Add(dr);
    }
    return dt;
  }

  void Page_Load(Object sender, EventArgs e)
  {
    if (!IsPostBack)
    {
      GridView1.DataSource = CreateDataTable();
      GridView1.DataBind();
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>Check/Uncheck All CheckBoxes in a GridView</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
  <script type="text/javascript">
    <!--
    $(function () {
      // ヘッダーの CheckBox にチェックを入れる/外すのと連
      // 動して、各行に配置した CheckBox すべてにチェックを
      // 入れる/外す。
      $('table tr th input:checkbox').click(function () {
        $('table tr td input:checkbox')
          .attr('checked', $(this).is(':checked'));
      });

      // 各行に配置した CheckBox のすべてにチェックが入った
      // 時、ヘッダーの CheckBox にもチェックを入れる。
      // 各行に配置した CheckBox の一つでもチェックを外すと、
      // ヘッダーの CheckBox のチェックが外れる。
      $('table tr td input:checkbox').click(function () {
        var chkAll =
          $('table tr td input:checkbox:not(:checked)')
            .length == 0 ? true : false;
        $('table tr th input:checkbox')
          .attr('checked', chkAll);
      });

      // [Check All]ボタンクリックで、すべての CheckBox
      // にチェックを入れる。
      $('#checkAll').click(function () {
        $('table input:checkbox').attr('checked', true);
      });

      // [Uncheck All]ボタンクリックで、すべての CheckBox 
      // のチェックを外す。
      $('#uncheckAll').click(function () {
        $('table input:checkbox').attr('checked', false);
      });
    });            
  //-->
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h2>Check/Uncheck All CheckBoxes</h2>
    <input type="button" 
      id="checkAll"
      value="Check All" /> 
    <input type="button" 
      id="uncheckAll"
      value="Uncheck All" />        
    <asp:GridView ID="GridView1" 
      runat="server" 
      AutoGenerateColumns="False">
      <Columns>
        <asp:TemplateField>
          <HeaderTemplate>
            <input id="Checkbox1" type="checkbox" />
          </HeaderTemplate>
          <ItemTemplate>
            <input id="Checkbox2" type="checkbox" />
          </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField HeaderText="Item" DataField="Item" />
        <asp:BoundField HeaderText="Name" DataField="Name" />
        <asp:BoundField HeaderText="Price" DataField="Price" />
      </Columns>
    </asp:GridView>    
  </div>
  </form>
</body>
</html>

------------ 2010/4/24 追記 ------------

この記事で紹介したコードを実際に動かして試せるよう 実験室 にアップしました。興味のある方は試してみてください。

Tags: , ,

JavaScript

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  October 2021  >>
MoTuWeThFrSaSu
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar