Hatena::ブログ(Diary)

on the center line.

2008-05-01

静的HTMLで、インクルードを実現するためのJavaScript

| 19:01

ローカルディスク上に存在する静的HTMLで、外部ファイルをインクルードするためのスクリプト(つまり、XMLHttpRequestオブジェクトの代わり)。

以前にも同じようなエントリを書いたのですが(http://d.hatena.ne.jp/kenpoco/20080228/1204198090)、いくつか不具合があったので修正してます。

  • IE6,7に対応(前回はFirefox2のみ)。
  • インクルードするファイルの拡張子が.HTMLと.TXTで動作が異なっていたので、その対応。
  • インクルードした後で、その内容を変更するための仕組みを追加。

最近HTMLを作る機会が多いので自分で使ってみてるのですが、けっこう重宝してます。全ページに同じようなヘッダー部分がある場合なんかに、ヘッダー部分を1ファイルにまとめておけるので、その後の修正がかなり楽。

【使用例】
-----------------------
 インクルード部分
-----------------------
<div>
   <script type="text/javascript" >
      include("a.html");    ←HTML内のインクルードしたいところに記入
   </script>
</div>

-----------------------
 インクルードされるファイル(a.html)
-----------------------
<div style="border: solid 1px #000000;">hello;</div>

-----------------------
 インクルード結果(表示後にinnerHTMLで確認)
-----------------------
<div>
   <script type="text/javascript" >
   </script>
   <div style="border: solid 1px #000000;">hello;</div>  ←includeした内容が<script>タグの下のところに入る
</div>
【関数本体】
-----------------------
function include(filename, afterfunc) {

  include.seq = (include.seq)? include.seq + 1: 1;

  var id = new Date().getTime() + "-" + include.seq;
  var inc = document.createElement("iframe");

  inc.id = "inc-" + id;
  inc.src = filename;
  inc.style.display = "none";
  document.write("<span id=\"" + id + "\"></span>");
    
  var incfunc = function() {
    
    var s = (function() {
      var suffix = (n = filename.lastIndexOf(".")) >= 0 ? filename.substring(n): "default";
      if (suffix == ".html") return inc.contentWindow.document.body.innerHTML;
      if (suffix == ".txt") return inc.contentWindow.document.body.firstChild.innerHTML;
      if (suffix == "default") return inc.contentWindow.document.body.innerHTML;
    })();

    var span = document.getElementById(id);

    var insertBeforeHTML = function(htmlStr, refNode) {
      if (document.createRange) {
        var range = document.createRange();
        range.setStartBefore(refNode);
        refNode.parentNode.insertBefore(range.createContextualFragment(htmlStr), refNode);
      } else {
        refNode.insertAdjacentHTML('BeforeBegin', htmlStr);
      }
    };

    insertBeforeHTML(s.split("&gt;").join(">").split("&lt;").join("<"), span);
    document.body.removeChild(inc);
    span.parentNode.removeChild(span);
    if (afterfunc) afterfunc();
  };

  if (window.attachEvent) {
    window.attachEvent('onload', 
      function() {
        document.body.appendChild(inc); 
        inc.onreadystatechange = function() { if (this.readyState == "complete") incfunc(); };
      });
  }
  else {
    document.body.appendChild(inc);
    inc.onload = incfunc;
  }
}

useruser 2009/07/29 10:16 ありがとうございます!
とっても便利です。使用させていただきます

yahooyahoo 2009/08/26 17:49 とても便利なのですが、こちらieで確認すると表示されますが、firefox3で確認するとインクルード部分表示されません。
そういうものでしょうか?

ゆきこゆきこ 2009/10/05 15:12 大変便利に使わせていただいております。
しかしながら、オペラでは見られないみたいで・・・。何か対応があれば教えていただけると助かります。あつかましいおねがいで失礼致します。

zeroxonezeroxone 2009/10/29 10:20 IE7で拡張子がtxtだとソースの一部分(最初の方だけ。削除すると下も表示される)しか表示されません。しかし拡張子をhtmlに変えたら問題なく表示されました。これって何が違うのでしょう?
firefoxはOKでした。

ぼんぼん 2009/11/29 22:45 使わせてもらってます。ありがとうございます。js でできるんですね。
ただinclude2か所試しましたが、1か所は反映されませんでした。
2か所は無理なんでしょうか?

ぶるるぶるる 2009/12/16 04:30 使わせていただてなんですが、firefox3.5だとまるっきり映りません。35行目にエラーと出ます。document.body.removeChild(inc); このあたりだと思うのですが。

老婆心老婆心 2010/09/04 21:53 include される HTML 内に、form の action が、あると、button の submit も、機能しないのは、何故でしょうか?

MasaYan21MasaYan21 2014/01/26 01:34 Chromeだと使えません。ローカルファイルだとアクセスに制限があるとか、ないとか?(T_T)
Uncaught SecurityError: Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match.

さぶろーさぶろー 2014/09/10 10:19 すばらしい!動かないっていう人はコードを読ませてもらいましょう。勉強になりますよ。なにはともあれ客先に提出用のサンプルを作るには最高です。ありがとうございます。

2008-03-18

imgタグの下にわずかなスペースができるときの解決策

| 11:17

例えば、以下のようなHTMLがあるとき

<div ><img src="aaa.jpg" />
</div>
テキスト

画像"aaa.jpg"と、"テキスト"との間に2〜3pxほどの隙間(ホワイトスペース)が

できてしまいます。これをなくすには、

<div ><img src="aaa.jpg" /></div>
テキスト

このように、<img>タグの後ろに改行をいれずに、閉じタグ</div>をつけてやります。

タグとタグの間の改行って、単純に無視されるものかと思ってましたが、

場合によっては意味あるんですね〜。

2008-02-28

JavaScriptを使ってHTMLのインクルードを実現しつつ、JSPでもインクルードできる方法

| 20:50

先のエントリにJSP版。これはあまりいけてないなあ。

●呼び出しイメージ
<script type="text/javascript" >//<%
  include("a.txt",request,response); //%>
</script>

スクリプト本体
<script type="text/javascript" >

var request;    // ←スクリプトエラーとならないように宣言
var response;
function include(filename) {
  include.seq = (include.seq)? include.seq + 1: 1;

  var id = new Date().getTime() + "-" + include.seq;
  var inc = document.createElement("iframe");

  inc.id = "inc-" + id;
  inc.src = filename;
  inc.style.display = "none";
  document.body.appendChild(inc);
  document.write("<span id=\"" + id + "\"></span>");
  
  var f = function() {
     inc = document.getElementById("inc-" + id);
     var s = inc.contentWindow.document.body.firstChild.innerHTML;
     document.getElementById(id).innerHTML = 
       s.split("&gt;").join(">").split("&lt;").join("<");
     document.body.removeChild(inc);
  };
  if (window.addEventListener) window.addEventListener('load', f, false);
  if (window.attachEvent) window.attachEvent('onload', f);
}

/*<%!
   void include(String filename, 
  		 javax.servlet.ServletRequest req, javax.servlet.ServletResponse res) 
			throws Exception {
   	req.getRequestDispatcher(filename).include(req, res);
   }
/**///%>

</script>

JSPの場合は、標準では<jsp:include>しかないので、includeメソッドを自作してます。ただ、JSPではメソッド内で暗黙の変数 request, response が使えないため、メソッドの呼び出しのときに引数が必要になってしまいます。残念。

JavaScriptを使ってHTMLのインクルードを実現しつつ、PHPでもインクルードできる方法

| 20:34

先のエントリを書きながら、そのままPHPのインクルードと併用できる書き方を思いつきました。

<script type="text/javascript">//<?php
  include("a.txt"); //?>
</script>

こうしておけば、ブラウザで読み込んだときはJavaScriptとして動くし、サーバで動かすときはPHPのインクルードとして動く。

これはもっと応用できるんじゃなかろうか。。。

JavaScriptを使ってHTMLのインクルードを実現する方法

| 20:28

純粋なHTMLだけでインクルードを実現するためのスクリプト

自分の環境でちょっと試した限りではちゃんと動いてそう。

■呼び出しイメージ
<tr><td>
    <script type="text/javascript">include("foo.txt");</script> ←これだけ
</td></tr>

■出力用JavaScript

function include(filename) {
  include.seq = (include.seq)? include.seq + 1: 1;

  var id = new Date().getTime() + "-" + include.seq;  // ←ユニークなID
  var inc = document.createElement("iframe");  // ←読み込み用の iframe

  inc.id = "inc-" + id;
  inc.src = filename;        // ←読み込む
  inc.style.display = "none";    // ←非表示にしておく
  document.body.appendChild(inc);
  document.write("<span id=\"" + id + "\"></span>");
  
  var f = function() {
     inc = document.getElementById("inc-" + id);
      // iframeの中より取得
     var s = inc.contentWindow.document.body.firstChild.innerHTML;
     document.getElementById(id).innerHTML = 
       s.split("&gt;").join(">").split("&lt;").join("<");
     document.body.removeChild(inc);
  };
  if (window.addEventListener) window.addEventListener('load', f, false);
  if (window.attachEvent) window.attachEvent('onload', f);
}

インクルードしたファイルをそのまま埋め込む方法が思いつかなくて、<span >の中に入れてるとこは改善したいのだが。

2008-02-19

position: relative;のテーブルの枠だけが表示されてしまう

| 11:57

IEで、非表示にしたはずのテーブルの枠だけが表示されるというなぞの現象。結局、原因わからず。

<html><body>
<a href="#"
 onclick="document.getElementById('div1').style.display = 'block';
 document.getElementById('div2').style.display = 'none';">1を表示(2は非表示)</a>
<a href="#"
 onclick="document.getElementById('div2').style.display = 'block';">2を表示</a>
<a href="#"
 onclick="document.getElementById('div1').style.display = 'none';">1,2を非表示に</a>

<div id="div1" style="position: absolute; border: solid 1px gray;" >[1]
  <div id="div2" >[2]
    <table style="position: relative; border: solid 1px gray;">
      <tr ><td >table</td></tr>
    </table>
  </div>
</div>

</body></html>