WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

マウスホイールでの操作

by WebSurfer 2010年10月21日 21:59
マウスホイールでリストボックスの選択を操作

マウスホイールを回すことによって発生するイベントを処置して、ブラウザ上に表示されたリストボックスの中のアイテムを選択する例を紹介します。

クライアント側だけの処置なので、ASP.NET はリストボックスなどの html を生成する以外にはあまり関係なく、マウスホイールのイベントの処置は、すべて JavaScript で行うことになります。

JavaScript の主要な部分は Mouse wheel programming in JavaScript というページからほぼ丸写しで、それにリストボックスの中のアイテムを選択するコードを追加しただけです。

だったら、そのページをリンクするだけでも済むのですが、将来リンク切れになると困るので自分のブログに書いておくことにしました。

コードは以下のとおりです。リストボックスにフォーカスを当てて、マウスホイールを回すと選択項目が変わるようになっています。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title></title>
  <script type="text/javascript">
  <!--
  // リストボックスの選択の操作
  function handle(delta) {
    if (document.activeElement.id == "myListBox") {
      var ddl = document.getElementById("myListBox");
      if (delta < 0) {
        if (ddl.selectedIndex < ddl.options.length - 1) {
          ddl.selectedIndex += 1;
        }
      } else {
        if (ddl.selectedIndex > 0) {
          ddl.selectedIndex -= 1;
        }
      }
    }
  }

  // マウスホイールイベントのハンドラ
  function wheel(event) {
    var delta = 0;

    if (!event) {
      event = window.event;   // IE の場合
    }

    if (event.wheelDelta) {
      delta = event.wheelDelta / 120;  // IE, Opera の場合
      if (window.opera) {
        delta = -delta;   // Opera は符合 (+/-) が異なる
      }
    } else if (event.detail) {
      // Mozilla は IE と符合 (+/-) が異なり、かつ
      // multiple factor は 3 になる。
      delta = -event.detail / 3;
    }

    // delta がゼロでなければハンドルする。
    // delta が正なら scroll up、負なら scroll down
    if (delta) {
      handle(delta);
    }

    // マウスホイールのデフォルトアクションの防止
    if (event.preventDefault) {
      event.preventDefault();
    }
    event.returnValue = false;
  }

  // 初期化用のコード
  if (window.addEventListener) {
    // DOMMouseScroll は mozilla 用
    window.addEventListener('DOMMouseScroll', wheel, false);
  }
  // IE/Opera 用
  window.onmousewheel = document.onmousewheel = wheel;
  //-->    
  </script>
</head>
<body>
  <h3>マウスホイールで選択操作</h3>
  <div>
    <select id="myListBox" name="myListBox" size="10">
      <option value="1">選択肢のサンプル1</option>
      <option value="2">選択肢のサンプル2</option>
      <option value="3">選択肢のサンプル3</option>
      <option value="4">選択肢のサンプル4</option>
      <option value="5">選択肢のサンプル5</option>
      <option value="6">選択肢のサンプル6</option>
      <option value="7">選択肢のサンプル7</option>
      <option value="8">選択肢のサンプル8</option>
      <option value="9">選択肢のサンプル9</option>
      <option value="10">選択肢のサンプル10</option>
    </select>
  </div>
</body>
</html>

JavaScript のコードでフォーカスの当たっている DOM エレメントを取得するため、 document.activeElement を使用しています。これは以前は IE のみで有効だったのですが、最近は ここ に書いてあるように、Firefox やその他のブラウザでもサポート済みのようです。実際、IE8, Firefox 3.6.11, Safari 5.0.2, Chrome 6.0.472.63, Opera 10.63 で確認しましたが、サポートしていました。

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

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

Tags:

JavaScript

絵文字の入力制限

by WebSurfer 2010年10月19日 21:02

MSDN フォーラムで、名前などの入力項目に携帯の絵文字を入力させないように、以下のステップで対応したいという話がありました。

  1. ユーザーのキャリアを判定
  2. キャリア別に入力の絵文字をチェック
  3. 絵文字が含まれていればエラー表示

フォーラムでは、このうち 2 番目のステップについて議論があり、自分が提案した方法でうまくいったそうですので、その内容を書いておきます。

ASP.NET の Web アプリのサーバー側のプログラムでは文字列は Unicode で扱われるので、絵文字に該当する Unicode 文字が分かれば、正規表現を使ってチェックできるはずです。

Wikipedia のページ 携帯電話の絵文字 によると、各キャリアの絵文字の Unicode 表現は以下のとおりとのことです。

  • au: E468-E5DF, EA80-EB88
  • DoCoMo: E63E-E6A5, E6AC-E6AE, E6B1-E6BA, E6CE-E757
  • SoftBank: E001-E05A, E101-E15A, E201-E253, E301-E34D, E401-E44C, E501-E537
  • emobile: E63E-E6A5, E6AC-E6AE, E6B1-E6BA, E6CE-E757, E600-E619

ユーザーが TextBox などに入力して POST した文字列をサーバー側で取得したとき、絵文字は上記の Unicode 文字になるはずです。

キャリア別に処置する必要がなければ、ちょっと乱暴かもしれませんが、外字全部(U+E000〜U+F8FF)を対象としてもいいかもしれません。

i絵文字

i-mode 絵文字入りの Shift_JIS コードを String 型の文字列 (Unicode) に変換し、正規表現を使って絵文字の有無のチェックおよび除去するサンプルを、C# のコンソールアプリで作って検証してみました。

ドコモが提供している絵文字入力ソフト「i絵文字」で、テキストファイルに簡単に i-mode 絵文字を挿入して試験できるのでお試しください。

全部の i-mode 絵文字を試したわけではありませんが、自分が試した限りでは i-mode 絵文字の有無のチェックおよび除去は以下のサンプルで可能でした。

au, Softbank, emobile も、上に紹介した「携帯電話の絵文字」のページの Unicode で pattern を作れば、チェックや除去は可能だと思います。

なお、ドコモ以外は検証していませんし、保証はできませんので、参考にするならご自分で十分検証してくださいね。

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace EmojiCheck
{
  class Program
  {
    static void Main(string[] args)
    {
      // testfile.txt は試験用の Shift_JIS のテキストファイル。

      string path = "testfile.txt";

      if (File.Exists(path))
      {
        string text = string.Empty;

        using (FileStream fs = File.Open(path, FileMode.Open))
        {
          byte[] b = new byte[(int)fs.Length];
          Encoding enc = Encoding.GetEncoding("shift_jis");
          fs.Read(b, 0, b.Length);
          text = enc.GetString(b);
        }

        Console.WriteLine(text);
        Console.WriteLine("----------------------------");

        // i-mode 絵文字の Unicode 表現
        string pattern = 
          @"[\uE63E-\uE6A5]|[\uE6AC-\uE6AE]|[\uE6B1-\uE6BA]|[\uE6CE-\uE757]";
        if (Regex.IsMatch(text, pattern))
        {
          Console.WriteLine("i-mode 絵文字があります。");
        }
        else
        {
          Console.WriteLine("i-mode 絵文字はありません。");
        }
        Console.WriteLine("----------------------------");

        // 絵文字を除去した文字列を取得
        Regex rgx = new Regex(pattern);
        string outputStr = rgx.Replace(text, "");
        Console.WriteLine(outputStr);
      }
    }
  }
}

Tags:

ASP.NET

ModalPopup で編集・更新操作

by WebSurfer 2010年10月14日 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

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar