Hatena::Grouporera

USOperaION/ε∂.∂з\ このページをアンテナに追加 RSSフィード

perl + MySQL で動く CMS W.S.O(うそ)作ってみました 使ってくれる人探してます工房らくだ舎
 | 

2006年03月23日(木)

[][] target 属性を無効にする例のあれ R  target 属性を無効にする例のあれ R - USOperaION/ε∂.∂з\ を含むブックマーク はてなブックマーク -  target 属性を無効にする例のあれ R - USOperaION/ε∂.∂з\  target 属性を無効にする例のあれ R - USOperaION/ε∂.∂з\ のブックマークコメント

なにげにリファを覗いていたら、 target 属性を無効にする例のあれを、引用しているところがいくつかあるようで。

あれは全然未完成で、場所によってはおかしな挙動をするところも少なくないと思うんで、そのまま使い続けるのはいかがなもんでしょう?そんなわけで、少し改善してみました。

disopenwin.js

まず、 Noriya さんスクリプトを参考に、フレームのページとそうでないページの処理を分けました。

フレームでないページの target は removeAttribute で全て削除します。ここまではほぼ Noriya さんのスクリプトのまま。

フレームページは、終点アンカーが外部の時と target のフレームが存在しない時は _top にします。なお、"window.framesにより子windowオブジェクトを取得し、それぞれのwindowオブジェクトについて再帰的に"処理するというのは、 user.js はフレームごとに実行されるはずなので、ナンセンスかと思われます。

/*	不正な target を _top に設定する*/
function setTopToIllegalTaget()
{
	for(var i in linkElements)
	{
		var items = window.document.getElementsByTagName(linkElements[i]);
		for (var j = 0 ; j < items.length ; j++)
		{
			var targetFrame	= items[j].getAttribute('target');
			var linkHref	= items[j].getAttribute('href') || items[j].getAttribute('action');
			//リンクが別のサイトの場合は _top に
			if(linkHref.indexOf(BaseHost) < 0)
			{
				items[j].setAttribute('target','_top');
			}
			else
			// target フレームが存在しない時は _top に
			if(targetFrame && !seekTargetFrame(top,targetFrame) && targetFrame != '_self' && targetFrame != '_parent')
			{
				items[j].setAttribute('target','_top');
			}
		}
	}
}

さて、これでたいがいのサイトは想定通りの挙動をしますが、フレームのページが異なるドメインのページである場合、セキュリティエラーで、スクリプトの実行が終了してしまいます。そこで、 top.document.frames を取得できないページは、先の処理を行う前に分岐します。

	if(!top.document.frames)						//トップのフレームコレクションを取得出来ない
	{
		outSiteTarget(w);
	}

で、分岐したところでどんな処理をさせたらいいもんかと悪戦苦闘の末、各要素に click イベントを追加して、 click 時に top.document.location = this.href; として無理矢理 top フレームに移動させることにした。

/*	top.document.location で強制移動	*/
function outSiteTarget()
{
	for(var i in linkElements)
	{
		var items = window.document.getElementsByTagName(linkElements[i]);
		for (var j = 0 ; j < items.length ; j++)
		{	// onclick イベントがない時だけ設定するようにしなくっちゃダメだけど、どうやってすればよいかな
			items[j].addEventListener
			('click',
				function()
				{
					top.document.location = this.href;	// これはアクセスできちゃうところがいまいち解せないが、そういう仕様なのだろう。
				},false
			);
		}
	}
}

で、あとは実行のタイミングなんですが、 load 時だけだと、読み込みが終わらないうちにクリックしたりすると新しいページが開いたりするんだよね。苦肉の策として click 時にも起動させたりしてみましたが、うまくないなぁ。もっと確実に実行できる方法はないもんですかね?

[][]window.open を抹殺する方法 window.open を抹殺する方法 - USOperaION/ε∂.∂з\ を含むブックマーク はてなブックマーク - window.open を抹殺する方法 - USOperaION/ε∂.∂з\ window.open を抹殺する方法 - USOperaION/ε∂.∂з\ のブックマークコメント

あと、 id:takeopera さんが余計なことはしないでほしいでふれられている、target="_blank" を使わないで新しいウィンドウでリンクを開く方法や、_blankを使わないで別ウィンドウを開くにはrel="external"を使うのが美しいと思う。なんかの、 window.open で新しいウィンドウを開くのを防ぐヤツは以下の感じでどうでしょうか?。やり方が正しいかどうか分かんないけど、これでだいたいのページは新しいウィンドウを開かずにリンク先を開くことが出来ます。

document.addEventListener
('load',
	function()
	{
		window.open = function(url,winName)
		{
			window.location	= url;
			window.name		= winName;
			return window;
		}
	},false
);

ちなみに、 load イベントにしているのは、そうしないと自動ポップアップのページに自動的に移動してしまうことがあるからです。自動ポップアップポップアップ抑制で殺してください。

usopionusopion2006/03/27 01:56return document; は return window; の方がいいかな?

usopionusopion2006/03/27 02:04window.open の 既定の返り値は多分ウィンドウオブジェクトだと思われるので、やっぱり return window; で。 return this; でもいいのかな?

usopionusopion2006/03/27 02:09return document; ではエラーだったところが return window; で直ったので、やはり return window; が正しいようだ。というわけで、 return window; に直した。

トラックバック - http://orera.g.hatena.ne.jp/usopion/20060323
 |