3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Qiitaの通知欄から各ユーザのプロフィールに移動できるユーザースクリプト

Posted at

概要

image.png

Qiitaの通知欄で各ユーザのアイコンやユーザ名をクリックすれば、そのユーザのプロフィールページへ直接移動できるようにするユーザースクリプトを作りました。

GreaseyForkで公開中です。

きっかけ

Qiitaの投稿画面の同時スクロールを改善するユーザースクリプト - Qiita

先日の記事は予想外の好評を頂きまして本当に驚きました。
Qiitaの通知欄にあんなに多くのいいね・ストックが集まるのは初めての経験でしたから嬉しい限りです。ありがとうございました。

さてところで、今から書くことは天才美少女プログラマーこと @itsminadesu 氏が某イベントで言ってたことのだいたいパクリなのですが―

image.png

Qiitaではいいね・ストックなどされたときの通知が画面右上の通知欄、あるいは通知一覧ページで確認できるようになっています。

この通知機能自体はTwitterのようなSNSでよくあるものですが、QiitaがTwitterと違うのは…

image.png

Twitterでは通知から「いいねした人」のプロフィールへリンクで移動できるようになっているのが、

image.png

Qiitaではそうではないという点です。

このせいでどんな人にいいね・ストックされたのか確認するのが面倒になっています。

まあどうしても確認したければ一応記事をいいねした人の一覧みたいなページもあるにはあるんですが、通知欄から直接移動できたほうが楽ではないでしょうか。

@itsminadesu 氏がそんなことを言ってたときはへーそんなもんかーくらいに思ってましたが今なら確かにそう思います。

そんなふうにできないかな、しましょう。

実装

言うて前回の記事でやったことに比べればずいぶん簡単です。

image.png

単純に各通知のアイコンの要素、またはユーザ名の要素をクリックしたらそのユーザのプロフィールページに移動できるようにしましょう。

image.png

また今回はJavaScriptを使ってページを移動させます。この方法だとaタグは使わないので、要素にマウスホバーしても下線が表示されません。

image.png

これだとクリックできるって分かりにくいので、マウスホバーで下線を表示する処理も手で書いておきましょう。

1. マウスクリックでプロフィールに移動

要素の取得

画面右上に出せる通知欄と、通知一覧ページのそれぞれで各通知のアイコンの要素とユーザ名の要素を取得したいと思います。

image.png

ここで幸いなのが、画面右上に出せる通知欄というのは基本的に通知一覧ページをiframe要素で埋め込んでるだけということです。

ユーザースクリプトはiframeで埋め込まれるページ内でも実行されるので、通知一覧ページのほうにだけ対応する実装をすれば自動的に画面右上に出せる通知欄でも同じ動作が実現されます。

そういうわけで実装にあたっては通知一覧ページのほうだけ見てればOK。取得には単純にCSSセレクタを使いましょう。

image.png

取得にあたって、アイコンはともかくユーザ名のほうに特別な属性が振られていないのが困りますが、ここではclass属性にboldが振られているspan要素2つのうち先に出てくる方がユーザ名だと推測することにします。

そういうわけで件の要素を取得するCSSセレクタは次の通りです。

document.querySelectorAllに渡すCSSセレクタ
.notification .notification_actionWrapper span.bold:first-child, .notification .notification_icon img

クリック処理の登録

またしても幸いなのが、Qiitaにはスクリーンネームとか無く、プロフィールページのURLは単純にhttps://qiita.com/<ユーザ名>だということと、

image.png

image.png

そのユーザ名は各通知のアイコンならalt属性、ユーザ名のほうなら中身のテキストノードにそのまま書かれているので、前項で取得した要素に含まれる情報からプロフィールページのURLが簡単に生成できるということです。

URLが生成できれば後は要素がクリックされたときにそのURLに移動させる処理さえ書けば大丈夫。
手っ取り早い実装法としては単にその要素をaタグで囲めば良いように思えますが…

image.png

Qiitaでは1つの通知全体が別のaタグで囲われており、どこをクリックしても関連する記事に移動されるようになっています。
自由度の高いHTML5でもさすがに親要素のaの中に子要素のaを入れることはできませんから別の方法を考えましょう。

別の方法となればJavaScriptです。極力aタグの挙動を再現することを目指して、

  • 普通に左クリックされた場合はparent.location.hrefプロパティを設定し、現在のウィンドウでURLを開く
  • 中クリックされた場合はwindow.open()メソッドを呼び出し、新しいウィンドウでURLを開く

というようにします。
Event.preventDefault()メソッドを呼び出して通常の通知クリック処理を止めるのを忘れないように、またlocation.hrefでなくparent.location.hrefを使ってiframeに埋め込まれている場合は親ウィンドウでURLを開くことも忘れないようにしましょう。

image.png

ちなみに忘れるとこうなります。これはこれで面白いんですけどね。

それとJavaScriptで左クリック時に発生するイベントはclick、中クリック時に発生するイベントはauxclickです。

// クリックされた時にリンクを開くメソッド
const handleClick = e => {
    e.preventDefault();
    const username = e.target.alt ? e.target.alt : e.target.textContent;
    parent.location.href = "/" + username;
};
const handleAuxclick = e => {
    e.preventDefault();
    const username = e.target.alt ? e.target.alt : e.target.textContent;
    open("/" + username);
    focus();
};

// 通知内にあるユーザ名またはアイコンの要素一覧を取得
const elements = document.querySelectorAll(".notification .notification_actionWrapper span.bold:first-child, .notification .notification_icon img");

// 要素それぞれにリンクを設定する
elements.forEach(element => {
    element.addEventListener("click", handleClick);
    element.addEventListener("auxclick", handleAuxclick);
});

2. マウスホバーで下線を引く

マウスホバー時に下線を引く方法としてはこの2つが考え付きます。

  • style要素を使いCSSで:hover疑似クラスを設定して下線を表示する方法
  • JavaScriptでマウスホバー時に下線を表示、ホバーが外れたときに下線を非表示にする方法

別にどっちでも良さそうですが、前項で作ったクリック処理との兼ね合いから後者の方法のほうがシンプルに実装できるので後者の方法を採ることにします。

JavaScriptでマウスホバー時に発生するイベントはmouseover、ホバーが外れたときに発生するイベントはmouseoutです。

// マウスホバーで下線を表示するメソッド
const handleMouseover = e => {
    e.target.style.textDecoration = "underline";
};
const handleMouseout = e => {
    e.target.style.textDecoration = "unset";
};

// 通知内にあるユーザ名またはアイコンの要素一覧を取得
const elements = document.querySelectorAll(".notification .notification_actionWrapper span.bold:first-child, .notification .notification_icon img");

elements.forEach(element => {
    element.addEventListener("mouseover", handleMouseover);
    element.addEventListener("mouseout", handleMouseout);
});

最終的に出来上がったコード

GitHubGreaseyForkで公開中です。

// ==UserScript==
// @name         Qiita通知ユーザーリンク
// @version      0.1
// @description  Qiitaの通知でいいねやストックしたユーザのプロフィールへのリンクを作り、どんなユーザにいいねされたのか確認しやすくする。
// @author       fukuchan
// @match        https://qiita.com/notifications*
// @grant        none
// ==/UserScript==

// クリックされた時にリンクを開くメソッド
const handleClick = e => {
    e.preventDefault();
    const username = e.target.alt ? e.target.alt : e.target.textContent;
    parent.location.href = "/" + username;
};
const handleAuxclick = e => {
    e.preventDefault();
    const username = e.target.alt ? e.target.alt : e.target.textContent;
    open("/" + username);
    focus();
};

// マウスホバーで下線を表示するメソッド
const handleMouseover = e => {
    e.target.style.textDecoration = "underline";
};
const handleMouseout = e => {
    e.target.style.textDecoration = "unset";
};

// 通知内にあるユーザ名またはアイコンの要素一覧を取得
const elements = document.querySelectorAll(".notification .notification_actionWrapper span.bold:first-child, .notification .notification_icon img");

// 要素それぞれにリンクを設定する
elements.forEach(element => {
    element.addEventListener("click", handleClick);
    element.addEventListener("auxclick", handleAuxclick);
    element.addEventListener("mouseover", handleMouseover);
    element.addEventListener("mouseout", handleMouseout);
});

Qiita - Mozilla Firefox 2020-03-06 20-01-57.gif

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?