>>2 にちょっとだけ書いたが、XFrames 1.0 の書式を拝借するテスト。
・使い方
(1). 下記のスクリプトを外部ファイル(例えば xframes.js)として保存。
(2). 全てのページに、<script type="text/javascript" type="xframes.js"></script> を埋め込む。
準備は以上。ページ内の a 要素をクリックしたときに、URI に frames() スキームがあるものだけに反応します。それ以外に影響はありません。
・書き方
URI に #frames() を置き、カッコ中に「フレーム名=URI」をコンマ区切りで並べます。数は自由。
<a href="#frames(frame1=example1.html,frame2=example2.html,frame3=example3.html)">
上記では、名前が frame1 のフレームに example1.html、名前が frame2 のフレームに example2.html、名前が frame3 のフレームに example3.html を表示します。対象は frame 要素でも iframe 要素でも可。
<a target="frame1" href="alt.html#frames(frame1=example1.html,frame2=example2.html)">
上記のように書けば、何らかの理由でスクリプトが動作しないとき、frame1 のフレームに alt.html を表示します。スクリプトが動作するときは、target 属性と alt.html は無視されます。
alt.html#frames(frame1=example1.html#frames(iframe1=example2.html))
上記のように入れ子にすれば、フレーム frame1 を example1.html にし、さらにその中の iframe 要素 iframe1 内を example2.html にします。ただし、frames() の入れ子は 3 階層まで。
・注意点
本来の XFrames の挙動とは異なります。また、フレーム名が重複した場合の動作は保証しません(手抜き)。IE では URI の長さ制限に引っ掛かるかもしれない。非スクリプト環境への代替措置としてはイマイチですが(個人的には別の方法をとる)、ないよりはマシ。
<a onclick=".."> なら数行で済むものを長々と書いているわけですが、リンクデータを URI に持たせれば、言語にも環境にも依存しない。利用者がリンク先を確認できるというのもそれなりにメリットかも。
if (/*@cc_on @if (@_jscript) @_jscript_version > 5.5 @else@*/
document.implementation &&
document.implementation.hasFeature ('Events', '2.0') &&
document.implementation.hasFeature ('HTML' , '2.0')
/*@end@*/)
(function () {
/************************************************************************/
function XFramesProcessor (evt) {
arguments.callee.prototype.handleEvent (evt);
return arguments.callee;
}
XFramesProcessor.prototype = {
uriReference : /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/,
associations : /([^=]+)=([^()]*(?:\([^()]*(?:\([^()]*\))?[^()]*\))?),?/g,
pointerPart : new RegExp ('(?:frames\\(' +
'((?:[^()^]|(?:\\^\\()|(?:\\^\\))|(?:\\^\\^)|(?:\\(' +
'(?:[^()^]|(?:\\^\\()|(?:\\^\\))|(?:\\^\\^)|(?:\\(' +
'(?:[^()^]|(?:\\^\\()|(?:\\^\\))|(?:\\^\\^)|(?:\\(' +
'(?:[^()^]|(?:\\^\\()|(?:\\^\\))|(?:\\^\\^)*)' +
'\\)))*' +
'\\)))*' +
'\\)))*)' +
'\\))?', ''),
handleEvent : function (evt) {
this[evt.type].call (this, evt);
},
load : function (evt) {
var data;
/*@if (@_jscript) detachEvent ('on' + @else@*/
removeEventListener (/*@end@*/ 'load', XFramesProcessor, false);
if (data = this.check (location)) {
this.parse (data);
}
},
click : function (evt) {
/*@if (@_jscript) var target = event.srcElement; @else@*/
var target = evt.target; /*@end@*/
var node, data;
if (node = this.contains (target, 'A')) {
if (data = this.check (node)) {
this.parse (data);
/*@if (@_jscript) event.returnValue = false; @else@*/
evt.preventDefault (); /*@end@*/
}
}
},
contains : function (node, tagName) {
do if (node.nodeName == tagName) break; while (node = node.parentNode);
return node;
},
check : function (uri) {
return this.pointerPart.exec (this.uriReference.exec (uri)[9])[1];
},
parse : function (data) {
for (var d; d = this.associations.exec (data); ) {
this.find (top.frames, decodeURIComponent (d[1]), decodeURIComponent (d[2]));
}
},
find : function (frames, id, uri) {
for (var i = 0, I = frames.length; i < I; i++) {
if (frames[i].id == id || frames[i].name == id) {
frames[i].location.href = uri;
}
if (frames[i].frames.length) {
this.find (frames[i].frames, id, uri);
}
}
}
};
/*@if (@_jscript)
attachEvent ('onload', XFramesProcessor);
document.attachEvent ('onclick', XFramesProcessor);
@else@*/
addEventListener ('load', XFramesProcessor, false);
document.addEventListener ('click', XFramesProcessor, false);
/*@end@*/
XFramesProcessor = null;
/************************************************************************/
} )();