Snow-Materia > Arekore-Trick-OUT

はじめに

「あれこれトリックあうと」 と読みます。
Arekore-Trick-Old-UserAgent-Trouble の略です。 どうでもいいですが。

標準に準拠していないような古いタイプのブラウザ (主にIE) で使いたいのに使えなかった機能を、 ちょっとだけ、それなりに、一部だけ、使えるようにして、
そのブラウザをだましだまし使ってしまおう、
そしたら HTMLとかJavaScriptも ちょっとは標準っぽく (けして標準で書けるというわけでわない) 書けたり見れたりするかも知れないね、
・・・といったツールです。

機能としては以下な感じ。
いずれも初期設定で使うか使わないかのスイッチはできます。

  1. <ABBR>をちゃんと解釈。 (IEのみ)
  2. <Q>とか指定した要素の前後にマーク。 (IEのみ)
  3. position:fixed;スタイルを擬似的に使う。 (IEのみ)
  4. <OBJECT>要素を<IFRAME>にする。 (IEのみ)
  5. document.getElementsByTagNameNS(ns, '*')等を使用可能に。
  6. 要素のelement.addEventListenerメソッドを使用可能に。
  7. 要素のelement.setAttribute('class', '*')を使用可能に。 (IEのみ)

それぞれの詳しい説明は、 「仕組みについて」 のところで説明してるので、そちらを参考に。
上のアンカーからでも飛べます。

おしらせ

2005/01/06
下記のように <IFRAME>に変換すると name属性が効かなくなるので 仕方なく対処(IEのみ)
2005/01/05-2
IEで不安定な <OBJECT>要素を <IFRAME>要素にする機能を追加。 (IEのみ)
2005/01/05
「前後にマーク」機能をCSSのセレクタ風味に使えるようにしてみました。
くわしくはマークの説明の中で。
2005/01/03
まとめてみました。

使い方について

JSファイルを読み込むだけです。

設置について

JavaScript
ArekoreTrick.js

仕組みについて

<ABBR>をちゃんと解釈。 (IEのみ)

<ABBR>IE だとちゃんと要素として認識してくれない ( <ABBR></ABBR>という 2つの空要素として認識されている ) ので、要素として再構成させます。

<Q>とかの要素の前後にマーク。 (IEのみ)

q:before, q:after { content:'"'; } も使えないのに、 Q要素の前後に最初からマークがつかないなんておかしい! ってことでマークがつくようにしちゃいます。

ソースのイメージとしては、例えば、 このヘアースタイルが<q>サザエさんみてェー</q>だとォ? とあったとすると、 このヘアースタイルが <q> <span class="mark">"</span> サザエさんみてェー <span class="mark">"</span> </q> だとォ? という風になります

マークやマークを代入する要素などは、JSの中で設定してください。
em.memo の前後に (~)カッコを挿入、みたいな。

スタイルシートでその文字部分を扱いたいときは、 q:before, q:after { content:'"'; }
q:before, q:after, q .mark { font-weight:bold; }
みたいにしてください。

CSSライクに、以下のような書き方に対応しました。
IDとクラスと属性はいくつでも連結できるハズです。

ただ、単に * とか .class だと、 ほぼ全ての要素にアクセスして判断するため、処理が非常にアホくさいです。 なるべく要素を指定したり、IDを指定して使うようにしませう。

  • *
  • A
  • #id
  • .class
  • #id.class
  • .class#id
  • A#id
  • A.class
  • A#id.class
  • A.class#id
  • A[title]
  • A[target="_blank"]
  • A EM
  • A #id
  • A .class
  • A EM SPAN
  • 以下略

ちょっとした専門用語を使うなら、 全称セレクタ, タイプセレクタ, IDセレクタ, クラスセレクタ, 子孫セレクタ, 属性セレクタの一部, が使えます。
子供セレクタ, 隣接セレクタ, 擬似クラス, には対応してません。
(たかだかIEで :before, :after するためにそこまで必要だとは思えないし/笑)

属性セレクタの一部というのは、基本的な A[title] A[target="_blank"] などはできて、ちょっと高度な A[rel~="help"] というスペースで区切られた値のリストでのマッチ、 Q[lang|="en"] というハイフンで区切られた値のリストのマッチ、 などはできない、ってことです。
…や、スクリプトの仕様とかじゃなく、 単にたいして使いそうもないのに そこまで対応させるのは無駄だし面倒だと思っただけです。 ごめん。

position:fixed;スタイルを擬似的に使う。 (IEのみ)

IEでは、スタイルシートで、 #banner { position:fixed; bottom:0; right:0; } とやっても固定されず、仕方なく #banner { position:absolute; bottom:0; right:0; } としても、画面をスクロールしたらすごくカッコ悪いことになります。

対応策として、IEと他のブラウザで場合わけして、こんな真似をしたり。↓

#banner {
    /* not IE */
    position:fixed !important;
    top:auto !important;
    bottom:0 !important;
    left:auto !important;
    right:0 !important;
    /* IE */
    position:absolute;
    top:0;
    bottom:auto;
    left:0;
    right:auto;
}

・・・と、するのもいいのですが、 ちゃんとできるに越したことはないので、 JSに値を設定することでそれなりに動くようにしてみました。
設定できる値は[px]での数値のみです。 ([em]とかは使えません)

<OBJECT>要素を<IFRAME>にする。

IEの場合、 <OBJECT>要素使うとなんか変なときがあるらしいので、 (メソッドを書き換えようとしたり、 for (key in object) したりするとIEが死にますw) 比較的安定に使える <IFRAME>要素に変換します。

MIMEタイプが なし, text/html, application/xhtml+xml, application/xml, text/xml, のいずれかのときだけ変換されます。

属性は data, id, name, class, title, width, height, border, のそれぞれが適当に保持されます。 他の値は消えます。

<IFRAME>要素に変換します。 などとは言ってますが、実際は要素を新しく作って、 <OBJECT>要素を消してるだけなので注意。

<IFRAME>に変換すると name属性が効かなくなる問題に対処しましたw
くわしくは、過去日記の OBJECT→IFRAME を参考に。

document.getElementsByTagNameNS(ns, '*')等を使用可能に。

getElementsByTagNameNScreateElementNS, createAttributeNS などはまだIEなどでは未定義で使えません。
なので、それぞれ getElementsByTagName, createElement, createAttribute によりオブジェクトを返すようにしてみました。

ただ、別に名前空間をサポートするわけじゃないので、 単に「エラーがでなくなる」という応急処置に過ぎません。 あしからず。

だいたい、バグなのか何なのかわからないけど、 Gecko や Opera でも、 ちゃんとXHTMLの名前空間指定したって var ps = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'P'); で要素とれないし。
当然 var ps = document.getElementsByTagNameNS(null, 'P'); ならとれるけど。
HTML, XHTML に限るなら、普通に var ps = document.getElementsByTagName('P'); ってやったほうがいいのカモ。

要素のelement.addEventListenerメソッドを使用可能に。

とりあえず、過去日記の JavaScriptのイベントのthis を参考に。

IEでも element.addEventListener を使えるようにします。
IE以外の使えなさそうなブラウザでも、大丈夫なはず。たぶん。おそらく。
Opera7.5では window.addEventListener だけ何故か使えないので、そのときだけ window.attachEvents が使われます。

イベントの発生する順序も、登録した順になります。

その他、これによるイベントのあれこれについては、 下の 要素に追加されるメソッドについて の項で解説します。

要素のelement.setAttribute('class', '*')を使用可能に。 (IEのみ)

IEでは element.setAttribute('class', '*');var clas = element.getAttribute('class'); では、classの値を取得・変更できず、 element.className = '*';var clas = element.className; とやらねばならないので、 setAttributegetAttribute をオーバーロードさせて、 class属性のときでも setAttributegetAttribute で属性を取得・変更できるようにしました。

これも、他のスクリプトで新しく要素を追加する場合は、 下の 要素に追加されるメソッドについて の項の、 他のスクリプト内で新しく要素を作る場合 の部分を参考に。

要素に追加されるメソッドについて

ここからは、この 仮想 addEventListener などを使って実際にスクリプトを作るときに注意することをまとめます。
一般に使う分には、あまり関係ないです。

イベントを発生させた要素のオブジェクト

addEventListener で発生させた要素のオブジェクトは、次のようにすると楽に取得できるかと。

function func(e) {
    var obj = this;    // element-object
    if (!obj.nodeType && e && e.srcElement)
        obj = e.target || e.srcElement;    // IE
    ...
}

windowオブジェクトの場合は e.srcElementがない(null)ので、 だいたいこれでいけると思います。

他のスクリプト内で新しく要素を作る場合

windowwindow.documentaddEventListener を関連付けるのは、 このJSファイルを読み込んでいるときですが、
ドキュメント内にある全ての要素に addEventListenersetAttribute, getAttribute などを関連付けするのは、 ドキュメントを読み終わったとき(onload時)になります。

そのため、スクリプト中で行われる、 document.createElement('DIV') とかには自動では関連付けされません。
( document.createElement.prototype.addEventListener とかできたらいいのに... )
その場合、次のように書くと結構シアワセになります。

var obj = document.createElement('DIV');
if (window.addElementMethod) addElementMethod(obj);

あとがき

s*m