opera:hige このページをアンテナに追加

2011-01-20

[][] tweet ボタンにタブキーでフォーカスがあたらない 01:06  tweet ボタンにタブキーでフォーカスがあたらない - opera:hige を含むブックマーク はてなブックマーク -  tweet ボタンにタブキーでフォーカスがあたらない - opera:hige

なぜフォーカスされないかというと a 要素でかかれているから。Opera はタブでフォーム要素*1のみをフォーカスしてくれる*2。それがあだとなったかたち。

それならばと button 要素で囲んでやればいいんじゃないかと思い UserJS を書いた。

// ==UserScript==
// @include http://twitter.com/*
// ==/UserScript==

window.addEventListener('DOMNodeInserted', function c() {
	var tweet_button = document.querySelector('.tweet-button');
	if(tweet_button) {
		window.removeEventListener('DOMNodeInserted', c, false);
		var button = document.createElement('button');
		button.appendChild(tweet_button.cloneNode(true));
		tweet_button.parentNode.replaceChild(button, tweet_button);
	}
}, false);

まず悩んだのが load や DOMContentLoaded のタイミングだと肝心のボタンがなくて動かない。

強引ではあるが、要素が追加されるタイミング(DOMNodeInserted*3 )すべてで実行している。ボタンが追加された時点で DOMNodeInserted をとめて a 要素を button 要素で囲むことにした。

結果、動かない。button 要素で囲んでいるにー。


次、先ほども書いたように通常だとフォーム要素以外はタブキーでフォーカスしないわけだが、tabindex 属性をつけてやるとフォーム要素以外でもフォーカスするようになる。書いてみた。

// ==UserScript==
// @include http://twitter.com/*
// ==/UserScript==

window.addEventListener('DOMNodeInserted', function c() {
	var tweet_button = document.querySelector('.tweet-button');
	if(tweet_button) {
		window.removeEventListener('DOMNodeInserted', c, false);
		tweet_button.setAttribute('tabindex', '1'); // 数字が微妙

	}
}, false);

またしても動かない。tabindex 属性ついてるのにー。


結果

わからん。

解決?

書いた。

// ==UserScript==
// @include http://twitter.com/*
// ==/UserScript==

window.addEventListener('DOMNodeInserted', function c() {
	var textarea = document.querySelector('.twitter-anywhere-tweet-box-editor');
	var tweet_button = document.querySelector('.tweet-button');
	if(tweet_button && textarea) {
		window.removeEventListener('DOMNodeInserted', c, false);
		var textarea_focus = false;
		textarea.addEventListener('focus', function() { textarea_focus = true; }, false);
		textarea.addEventListener('blur', function() { textarea_focus = false; }, false);
		textarea.addEventListener('keyup', function(e) {
			if(e.keyCode == 13 && e.ctrlKey && textarea_focus) {
				e.preventDefault();
				tweet_button.click();
			}
		}, false);
	}
}, false);

動いた。

Replyの時に使う擬似ウィンドウでは動かない。

追記

// ==UserScript==
// @include http://twitter.com/*
// ==/UserScript==

window.addEventListener('DOMNodeInserted', function (e) {
	var f = e.target.firstElementChild;
	if(f && f.className == 'main-content') { 
		addTweetEvent(f.querySelector('.twitter-anywhere-tweet-box-editor'), f.querySelector('.tweet-button'));
	} else if(e.target.className == 'twitter-anywhere-tweet-box-editor') {
		addTweetEvent(e.target, document.querySelector('.twttr-dialog-container').querySelector('.tweet-button'))
	}
	function addTweetEvent(textarea, tweet_button) {
		var textarea_focus = false;
		textarea.addEventListener('focus', function() { textarea_focus = true; }, false);
		textarea.addEventListener('blur', function() { textarea_focus = false; }, false);
		textarea.addEventListener('keyup', function(e) {
			if(e.keyCode == 13 && e.ctrlKey && textarea_focus) {
			e.preventDefault();
				tweet_button.click();
			}
		}, false);
	}
}, false);

リプライダイアログでも動くようにした。 firstElementChild 便利。

firstElementChild などについて

Element Traversal API - 三等兵


OK?

またもや edvakf さんの助言より

// @include http://twitter.com/*
// ==/UserScript==

window.addEventListener('keypress', function(e) {
	if(e.keyCode === 13 && e.ctrlKey && document.activeElement.className === 'twitter-anywhere-tweet-box-editor') {
		var button = document.activeElement.parentNode.parentNode.parentNode.querySelector('.tweet-button');
		button.click();
	}
}, true);
ポイント
  • テキストエリアはイベントが伝播しないので addEventListener の第3引数を true にして window にイベントを渡している。
  • document.activeElement でフォーカスのあたっている要素を取れる*4

*1:input, button textarea etc.

*2Opera のすばらしいところ

*3:初めて知った。便利そう。

*4:知らなかった

トラックバック - http://orera.g.hatena.ne.jp/higeorange/20110120