« 2006年11月 | トップページ | 2007年1月 »

2006年12月26日 (火)

[JavaScript]JavaScriptでiframeの中身の操作

前回、「iframe」タグを用いたメニューの作成方法をご紹介しました。この方法だとIEでも後ろの「select」タグがきちんと隠れるように表示できます。
しかし、この方法だと「div」タグを使用した方法のように表示のサイズをないように応じて動的に変更させたい場合には、うまくいきません。
今回は、それを回避できる方法をご紹介したいと思います。ただし、この方法はIE以外ではあまりうまくいかないのでブラウザごとに処理を分けてIEでのみ実施したほうがいいです。

方法といってもそれほど難しい方法ではなく単純に「iframe」タグの中身を動的にJavaScriptで書き換えるのと「iframe」タグのスタイルで「width」と「height」に値をあたえて大きさを調整するといった方法です。

では、実際のサンプルです。メニューは、サブメニューのリンクをクリックして閉じてください。

メニュー ⇒

中身を見ていくと

HTMLの内容
<div id="topmenu" class="topmenu" style="width:6em;float:left;" onmouseover="showmenu( 'sample' );">メニュー ⇒</div><div>
 <iframe id="sample3" class="submenu" style="display:none;z-index:1000;" frameborder="0"></iframe>

JavaScriptの内容
function show_iframe( id )
{
  var target = document.getElementById( id );

  var idoc = null;
  if( target.contentDocument )
    idoc = target.contentDocument;
  else
    idoc = document.frames[id].document;

  html  = '<html><head><title></title><head><body style="margin:0px">\r\n';
  html += '<table style="width:100%;margin:0px">\r\n';
  html += '<tr><td style="white-space:nowrap"><a href="#" onclick="window.parent.close_iframe( \'sample\' )">サブメニュー1</a></td></tr>\r\n';
  html += '<tr><td style="white-space:nowrap"><a href="#" onclick="window.parent.close_iframe( \'sample\' )">サブメニュー2</a></td></tr>\r\n';
  html += '<tr><td style="white-space:nowrap"><a href="#" onclick="window.parent.close_iframe( \'sample\' )">サブメニュー3</a></td></tr>\r\n';
  html += '<tr><td style="white-space:nowrap"><a href="#" onclick="window.parent.close_iframe( \'sample\' )">ちょっと長くなったサブメニュー4</a></td></tr>\r\n';
  html += '<tr><td style="white-space:nowrap"><a href="#" onclick="window.parent.close_iframe( \'sample\' )">さらにちょっと長くなったサブメニュー5</a></td></tr>\r\n';
  html += '</table>\r\n';
  html += '</body></html>\r\n';

  idoc.open();
  idoc.write( html );
  idoc.close();

  target.style.display = '';

  idoc.body.offsetHeight;
  idoc.body.offsetWidth;
  target.style.height = idoc.body.scrollHeight;
  target.style.width = idoc.body.scrollWidth;
}

function close_iframe( id )
{
  var target = document.getElementById( id );
  target.style.display = 'none';
}

JavaScriptの内容は、iframe内のdocumentオブジェクトを取得してそれにHTMLの内容を書き込んでいます。ドキュメントとの取得方法は、IEとFireFoxで違っていてFireFoxでは「target.contentDocument」、IEでは「document.frames[id].document;」として取得しています。
取得したオブジェクトに対して「open」「write」「close」で内容を書き込んでいきます。

その後、サイズを繁栄させるのですが、このままではまだ画面に表示していないので実際のサイズはわかりません。そこで一度、「target.style.display='';」を実行して表示させてから、画面のサイズを取得しています。
ここでなぜか、関係のない

  idoc.body.offsetHeight;
  idoc.body.offsetWidth;

を行っていますが、これはその後の「idoc.body.scrollHeight」で値を取得するために呼び出しています。なぜかわかりませんが一度、この呼び出し(どちらか一方でいいです)をしないときちんと取れなかったので呼び出しています。

あとは、取得した表示領域の大きさを「iframe」タグに反映させれば、うまい具合に表示されるようになります。

この方法で問題があるのが、MacのSafariで動作しないということです。おそらくセキュリティの問題とは、思われますが気をつけてください。
それと当然のことですが、「iframe」タグ内にドメインの違うHTMLを表示するとセキュリティ上の制約で操作できないので「src」には、何も記述しないようにしてください。

1つにまとめたサンプルです。

今回の記事で今年は、終わりになります。今年は、独立したりといろいろ激動の年になりましたが来年はいよいよ製品のリリースをして本格的なスタートを行いたいと思っています。
来年もよろしくお願いいたします。

| | コメント (0) | トラックバック (0)

2006年12月19日 (火)

[JavaScript]JavaScriptで作るメニュー パート3

前回までのJavaScriptで、ダイアログやメニューなどを作成してきましたが、実はIEの場合のみある条件であまりよろしくない状態になってしまうことがあります。
それは、「div」の指定で「position:absolute」の指定をして表示した場合に表示している領域の下に「select」タグがあるとそちらが表示されてしまうという現象が発生します。

実際に行ってみるとこんな感じになります。

メニュー ⇒

このようにIEでは、「z-index」をいくら大きくしても下にある「select」タグの内容が表示されてしまいせっかく作ったダイアログやメニューが台無しになってしまいます。

しかし、これについて回避する方法があります。それは、「iframe」を使用することにより回避できるようになります。
「iframe」タグは、インラインフレームのことでHTMLのページの中にほかのページを埋め込むことができる機能です。

実際にやってみるとこのようになります。

メニュー ⇒

これで、IEでも問題なくダイアログやメニューが表示できるようになります。

中身を見ていくと

HTMLの内容
<div id="topmenu" class="topmenu" style="width:6em;float:left;" onmouseover="showmenu( this, 'sample3' );" onmouseout="hiddenmenu( 'sample3' );">メニュー ⇒</div><div><select>
 <option>選択1</option>
 <option>選択2</option>
 <option>選択3</option>
 <option>選択4</option>
 <option>選択5</option>
</select></div>
 <iframe id="sample3" class="submenu" style="display:none;z-index:1000;height:6.6em;" frameborder="0" src="http://at-shima.cocolog-nifty.com/sample/menu3_iframe.html" onmouseover="onmousemenu( 'sample3' );" onmouseout="hiddenmenu( 'sample3' );"></iframe>

iframeで読み込んでいるHTMLの内容
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
<head>
 <meta http-equiv="content-type" content="text/html;charset=UTF-8">
 <meta http-equiv="Content-Style-Type" content="text/css">
 <meta http-equiv="Content-Script-Type" content="text/javascript">
 <link href="http://at-shima.cocolog-nifty.com/css/menu.css" type="text/css" rel="stylesheet" />
</head>
<body style="margin:0px;padding:0px;">
  <div class="menuitem"><a class="menuitem" href="#" onclick="window.parent.closeMenu( 'sample3' );return false;">サブメニュー1</a></div>
  <div class="menuitem"><a class="menuitem"  href="#" onclick="window.parent.closeMenu( 'sample3' );return false;">サブメニュー2</a></div>
  <div class="menuitem"><a class="menuitem"  href="#" onclick="window.parent.closeMenu( 'sample3' );return false;">サブメニュー3</a></div>
  <div class="menuitem"><a class="menuitem"  href="#" onclick="window.parent.closeMenu( 'sample3' );return false;">サブメニュー4</a></div>
  <div class="menuitem"><a class="menuitem"  href="#" onclick="window.parent.closeMenu( 'sample3' );return false;">サブメニュー5</a></div>
</body>
</html>

「iframe」タグで読み込んでいる内容とHTMLの中身が変わっただけでスタイルシートやJavaScriptの内容は、[JavaScript]JavaScriptで作るメニューと同じ内容になっています。イガっているのは、メニューの表示部分で「iframe」を使用しているということだけになります。

「iframe」タグの中でメニューを閉じるために「window.parent.closeMenu( 'sample3' );」と呼び出していますがこれは、iframeを読んでいるウインドウ(トップメニューがあるほうのWindow)のJavaScriptを呼び出していることになります。

注意点としては、「iframe」タグで呼び出すHTMLの中身はそれ自体で表示されるHTMLとして記述する必要があるので「html」タグからきちんと記述する必要があります。当然別のHTMLとして記述するので必要なスタイルシートやJavaScriptもきちんと記述する必要があります。
あと、基本的には「iframe」タグを使用するのは、IEのみにしてほかのブラウザで表示する場合には、前回までの表示方法を使用することをお勧めします。「iframe」タグは別のHTMLを表示していることになるので2回サーバーに対してリクエストを発行することになりますし、表示の大きさなどをきちんと指定しないとスクロールバーが表示されたりします。これがすべてのブラウザで同じ場合はいいのですがIEとFireFoxで表示する大きさがちょっとずつ違っているので大変なことになります。

1つにまとめたサンプルです。

| | コメント (0) | トラックバック (0)

2006年12月 8日 (金)

JavaScript]JavaScriptで作るメニュー パート2

今回は、前回に引き続きJavaScriptでメニューの作成を行いたいと思います。

前回の動的なメニューの作成では、マウスがメニューから外れてしまうと開いていたプルダウンメニューが勝手に消えてしまうので実際に使用していると使い勝手が悪かったりします。
そこで今回のメニューではプルダウンで開いたメニューが、メニューの領域以外の画面のほかの部分をクリックしたときに閉じるようにしてみたいと思います。

メニュー ⇒

中身をみていくと

HTMLの内容
<div id="topmenu" class="topmenu" style="width:6em;" onclick="showmenu2( 'sample1' );">メニュー ⇒</div>
 <div id="sample1" class="submenu" style="display:none;">
  <div class="menuitem"><a class="menuitem" href="" onclick="alert( 'サブメニュー1' );closeMenu2();return false;">サブメニュー1</a></div>
  <div class="menuitem"><a class="menuitem" href="" onclick="alert( 'サブメニュー2' );closeMenu2();return false;">サブメニュー2</a></div>
  <div class="menuitem"><a class="menuitem" href="" onclick="alert( 'サブメニュー3' );closeMenu2();return false;">サブメニュー3</a></div>
  <div class="menuitem"><a class="menuitem" href="" onclick="alert( 'サブメニュー4' );closeMenu2();return false;">サブメニュー4</a></div>
  <div class="menuitem"><a class="menuitem" href="" onclick="alert( 'サブメニュー5' );closeMenu2();return false;">サブメニュー5</a></div>
</div>

読み込んでいるCSSファイルの内容(前回と同じです)
.topmenu {
 border:solid 1px gray;
}

.submenu {
 width: 10em;
 background-color:white;
 border:solid 1px gray;
 position: absolute;
 z-index:1000;
}
.menuitem {
 width:100%;
 white-space:nowrap;
 border-bottom:solid 1px gray;
 margin:0;
}

a.menuitem:link{
 text-decoration:none;
}
a.menuitem:visited{
 text-decoration:none;
}
a.menuitem:hover{
 text-decoration:none;
 background-color:lightcyan;
}
a.menuitem:active{
 text-decoration:none;
 background-color:lightcyan;
}

JavaScriptの内容
var menuobj = null;
var menu_id = null;

function showmenu2( id )
{
  var target = document.getElementById( id );

  target.style.display = '';
  
  menuobj = new Rect(0,0,0,0);
  menuobj.getElementRect( target );
  menu_id = id;
}

document.onmousedown = function( e )
{
 if( ! menuobj  ) return;

  var target = document.getElementById( menu_id );

  if( target.display != 'none' )
  {
    var pt = null;
    if( document.all )
    {
      pt = new Point(event.x , event.y );
    }
    else
    {
      pt = new Point(e.pageX , e.pageY );
    }

    if( ! menuobj.PtInRect( pt ) )
    {
      menuobj = null;
      target.style.display = 'none';
    }
  }

  return true;
}

function  closeMenu2()
{
  var target = document.getElementById( menu_id );
  if( target )
  {
    target.style.display = 'none';
  }
  menuobj = null;
  menu_id = null;
}

function Rect( x, y, width, height )
{
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
  
}

Rect.prototype.getElementRect = function( target )
{
  if( target.display != 'none' )
  {
    var top = target.offsetTop;
    var left = target.offsetLeft;
    var obj = target.offsetParent;
    for( ;; )
    {
      if( ! obj )
        break;

      top += obj.offsetTop;
      left += obj.offsetLeft;

      obj = obj.offsetParent;
    }

    this.x = left;
    this.y = top;
    this.width = target.offsetWidth;
    this.height = target.offsetHeight;

    return true;
  }

  return false;
}

Rect.prototype.PtInRect = function(point)
{
  if( this.x > point.x || (this.x+this.width ) < point.x )
   return false;
  if( this.y > point.y || (this.y+this.height ) < point.y )
   return false;

  return true;
}

Rect.prototype.toString = function()
{
  return 'X:' + this.x + ' Y:' + this.y + ' Width:' + this.width + ' Height:' + this.height;
}

function Point( x, y )
{
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function()
{
  return 'X:' + this.x + ' Y:' + this.y;
}

となっています。

中身を見ていくといつものようにプルダウンの部分を「display:none;」で隠しておいてトップメニューをクリックしたときにそれを表示るようにしています。
そしてプルダウンメニューの部分の領域を保存しておいて、マウスをクリックしたときにその保存しておいた領域外でイベントが発生してたときにプルダウンメニューを再び隠すということを行っています。

このJavaScriptの中で「Rect」と「Point」がありますがこれは「function」を用いてユーザー定義の独自のクラスを定義してます。
このように独自のクラスを用いることでオブジェクト指向な実装をすることが可能になっています。

1つにまとめたサンプルです。

| | コメント (0) | トラックバック (0)

« 2006年11月 | トップページ | 2007年1月 »