flandlescarlet's diary【情報工学生の備忘録】

元機械工学科所属だった情報工学生です。JavaScriptで適当に何かを作ったり、絵を描いていたりします。

JavaScriptでgreasemonkeyを作成する方法4

新規フォームの作成をする

今回は実際に前回のイベント作成を利用して、はてなメッセージに便利なコンテンツを設けようと思います。

設ける物

今回はgreasemonkeyの一歩という事ではてな検索その物のフォームを、はてなメッセージに追加させようと思います。

追加させる際には二通りの方法があります

  • innerHTMLで直接既存のコンテンツの後ろに新しいコンテンツを追加する。
  • createElement,appendChildを使い既存のコンテンツの後ろに新しいコンテンツを追加する。

初心のうちは前者の方が使いやすいかと思います。

Sample1 : innerHTMLの場合

(function(){

document.getElementById("header-body").innerHTML += '<input type="text" id="contentText"><input type="button" id="contentButton" value="検索">';

})();

Sample2 : createElement,appendChildの場合

(function(){

formInput = document.createElement("input"); //text用
formButton = document.createElement("input"); //button用

/* text用フォームの製作 */

formInput.type = "text";
formInput.id = "textContent";

/* button用フォームの製作*/

formButton.type = "button";
formButton.id = "buttonContent";
formButton.value = "検索";

document.getElementById("header-body").appendChild(formInput);
document.getElementById("header-body").appendChild(formButton);

})();

どちらも同じ検索フォームが出来上がります。

Image1

image01

基本的に短いコンテンツであれば速度を重視してinnerHTMLを用いると良いですが

複雑なコンテンツを作成しようと思った場合オブジェクトで各属性を決定するcreateElementでコンテンツを作成してappendChildでまとめてコンテンツを追加する方が容易です。

基本的に両方の方法でイベントが作れるようにソースを記述していきます。

ボタンをクリックするとアラート表示

前回説明した、addEventListenerを使い各イベントに応じての処理わけを行います

Sample3

 	document.getElementById("buttonContent").addEventListener("click",function(){

alert("");

},"true");

コードはさっきの続きに記入するという形になります。

document.getElementで先ほど作成したボタンのid名を取得します(innerHTML , createElementで共にid名を作成)オブジェクトとしてaddEventListener(,,)を繋げます。引数は3つ(onを除いたイベントの種類 , 関数(無名関数で直接書いても良い) , true及びfalse(基本的にtrue))

今回は関数名の無駄な消費を抑えるため無名関数で直接書いていきます。

これでid名(buttonContent)を持つ要素(検索ボタン)を押すと(click)関数が呼び出され中にあるアラートが呼び起こされる。という形になります。

これに最後の仕上げとして、はてなの検索フォームに変えます。

はてな検索の移動にはlocation.hrefを用います。

 

Sample4 : はてな検索フォームの仕組み

http://search.hatena.ne.jp/search?word= [ここに検索する内容の文字列が入る]

上記のURLははてな検索で実際に単語を検索して返されたURLになります。

検索フォームを使わなくても意図的にURLに任意の単語を決められた場所に入れ検索するとその検索結果が返ってきます。

これにより以下のソースを生成します。

Sample5

 	document.getElementById("buttonContent").addEventListener("click",function(){

textContentValue = document.getElementById("textContent").value;
location.href = "http://search.hatena.ne.jp/search?word=" + textContentValue;

},"true");

getElementByIdで取得しているのはテキストフォームのvalue値です。

基本的にボタンとテキストフォーム両方にid名をつけましたのでそれからユーザーが入力した値を参照します。後は検索結果の表示となるわけですが、文字には文字コードという問題が必ずついてきます。URLの文字列は必ずエンコードしなければなりません。そのため結果的に英数字以外では文字化けしてしまいます。基本的に大手の検索フォームには文字コードを設定するプロパティがあるのですが、はてなには無いようですので今回作成する検索フォームはここまでとします。

以下今回の全体のソース

Sample6

 // ==UserScript==
// @name Hatena Message Form
// @namespace http://www.hatena.ne.jp/
// @author flandlescalet
// @description Hatena search box append
// @include http://m.hatena.ne.jp/*
// @exclude http://yahoo.co.jp/
// ==/UserScript==


(function(){

formInput = document.createElement("input"); //text用
formButton = document.createElement("input"); //button用

/* text用フォームの製作 */

formInput.type = "text";
formInput.id = "textContent";

/* button用フォームの製作*/

formButton.type = "button";
formButton.id = "buttonContent";
formButton.value = "検索";

document.getElementById("header-body").appendChild(formInput);
document.getElementById("header-body").appendChild(formButton);

document.getElementById("buttonContent").addEventListener("click",function(){

textContentValue = document.getElementById("textContent").value;
location.href = "http://search.hatena.ne.jp/search?word=" + textContentValue;

},"true");




})();

今まで1~4の内容を踏まえれば大抵の事はgreasemonkeyで製作することが可能となります。

greasemonkeyは特別なJavaScriptといった感じがしますが、決してそうではなくDOMの概念を深くもったJavaScriptの一つであることを捉えておく必要があります。

データの取得にはgetElementだけでなくXPATHといった方法もありますのでいろいろパターンを探して自分なりのソースの記述を見つけると良いかもしれません。

JavaScriptライブラリthree.jsで作成された3D作品の中でお勧めをピックアップ

Webで見る3Dのサイト

前回記事で話したthree.jsですが本格的に見てみると他にも興味深い作品もありましたので

説明も加えて紹介させていただきます。

voxels

http://mrdoob.com/projects/voxels/

概要としてはブロックをユーザーが操作して作品を制作していくものです。

操作としては、0-9キーでカラー選択を行い、マウスドラッグで視点切り替えで行います。shift+Clickで作成したボックスを削除します。矢印キーで製作場所の移動が可能となります。製作してみたところかなり広い範囲で作成出来るようです。ブロックが遠くなった場合は視覚上消えますが、再度元の場所に製作場所を戻せばブロックは視覚内に戻ってきます。

 

 Rome

http://www.ro.me/

ほとんど閲覧という形になりますが、最初のムービー以外は全てJavaScriptによる絵画で3Dムービーを再現しています。

面白いところはマウスカーソルが直接、視点切り替えになり、途中建築物のようなステージの場所に辿り付きますが、カーソルを当てたところに自然が生まれるようですね。これはなかなか面白いと思いました。ちなみにFirefoxで閲覧しましたが、負荷が重いのか途中で強制終了させられましたので軽量な状態の時に閲覧してみると最後まで見れるかと思います。

 

aquarium

http://webglsamples.googlecode.com/hg/aquarium/aquarium.html

この水族館もなかなか綺麗でJavaScriptで製作したとは思えない完成度です。

メニューから魚の数を変えることができ他にも水族館の見る視点を変えることも出来ます。

 

World Population

http://data-arts.appspot.com/globe

これは地球全体の人口を見る模式図みたいなものですね。

年代が3つ用意されており、それぞれの人口量を3Dのグラフとして現地に絵画しています。グラフならば2Dでcanvasを用いて作成できるのですが。three.jsを用いれば3D空間にも絵画出来るようになるのですね。

3Dで世界を作れるthree.jsが凄い

3Dならなんでも出来るthree.js

最近canvas関係について勉強していると面白いライブラリを発見しました。

three.js

https://github.com/mrdoob/three.js/

実際に製作されて公開されている物もありましたので挙げておきます

http://mrdoob.github.com/three.js/examples/webgl_geometry_minecraft_ao.html

Image1

上の作品ですが、実際にマウスでクリックして移動することができちゃいます。

まだイベント等はありませんが、JavaScriptの大きな進歩が見えるひとつの作品だと思いました。

3Dという概念ではhsp言語とかC言語方面に任せることになりますが、本当にWebで作ってしまうとは...

フィードバックに要請を出しました

 デバッグと機能の追加要求

とりあえず気になることが二点ありましたのでフィードバックに出させていただきました。

  • 見たまま編集でテキストをドラッグしてB(Bold)効果を与えたあと、続けてフォントサイズを大きくする効果のボタンをクリックしても何も起こらないバグの解消(bold効果は反映されるがフォントサイズ大を何度押しても効果が得られない)
  • <pre>タグを見たまま編集で常時追加出来るボタンの追加希望

1番目の場合先にフォントサイズを大きくして後にboldさせるという方法でバグを回避できますが一応修正してほしいバグです。

二番目は単にhtml編集で毎度<pre>タグを挿入する作業はめんどいという理由で要望を出しました。

JavaScriptでgreasemonkeyを作成する方法3

クリックによるイベント作成

前回記事:http://yatagarasu0495.hatenablog.jp/entry/2012/02/27/235214

前回まではCSS関連の変化(動的なユーザーの介入が無い)でしたが

今回は実際にクリック、マウスを乗せるなどのイベント操作でサイトを操作していこうと思います。

各class名やid名及びtag名の抜き取りで一番簡単な方法を再度記述しておきます。

(最終的にはXPATHで各場所を指摘できるようになると良い)

Sample1 : HTML , JavaScript

<div id="menu" class="design" name="user">
<div id="content" class="design" name="user">
<img src="image.png">
</div></div>  
// ==UserScript==
// @
// ==/UserScript==

//id名で取得する document.getElementById

id_menu = document.getElementById("menu");
id_content = document.getElementById("content");

//class名で取得する documents.getElementByClassName

section1 = document.getElementsByClassName("section")[0];
section2 = document.getElementsByClassName("section")[1];
alert(document.getElementsByClassName("section").length);//個数表示する

//tag名で取得する document.getElementsByTagName

div1 = document.getElementsByTagName("div")[0];
div2 = document.getElementsByTagName("div")[1];
img1 = document.getElementsByTagName("img")[0];

これがid名、class名そしてtag名での取得となります。

気をつける点はidとcalss,tagの定義で、idは一つだけしか存在してはいけない物であるためelement(要素)は複数系にならず値もそのまま格納されます。

しかしclassとtagは個数が複数あるためelementが複数系となりsが付き

更に値は配列として保存されるということに注意しましょう。

 

クリックイベントの追加

では以上の事を踏まえたうえで実際にある箇所をクリックしてアラートを出す処理をしてみましょう。

使用するサイトは前回同様にはてなメッセージで行います。

まずは実際にサンプルを書いてみます。

Sample2 : HTML , JavaScript

<!-- はてなメッセージのお知らせ部分のリンクの一部 -->

<a class="message-title" href="/tree?9258791470029364816">[Hatena::Ugomemo]
</a>
 // ==UserScript==
// @include http://m.hatena.ne.jp
// ==/UserScript==

message = document.getElementsByClassName("message-title")[0];
message.onclick = function(){ alert(Hello World!!); }

とりあえず、この形にします。

DOMの概念ですが基本的にdocument.getElement("").XXXXX getElementの後ろは"style","イベントハンドラ","innerHTML","ノード関係"これらのオブジェクトが続いていくという形になります。

基本的にこの4つを書けるようにすれば実質万能にサイトは操作が可能になります。

今回のソースはハンドラをelementの後ろにつけるという形にしましたが、もう少し綺麗な書き方があります。

Sample3

 // ==UserScript==
// @include http://m.hatena.ne.jp
// ==/UserScript==

message = document.getElementsByClassName("message-title")[0];
message.onclick = function(){ alert(Hello World!!); }

message.addEventListener("click",function(){alert("");},"true");

addEventListenerというものを使います、引数は3つでそれぞれ

"イベントの種類"、"実行する関数の変数及び無名関数でそのまま記述","基本的にtrueを無難に記述"となります。

前半の引数の2つを覚えておくと良いでしょう。

イベントの種類はonを除く("click","mouseover","mouseout")などが該当します

関数は無名関数でかけるのと、変数を表記して関数を呼び出せるのも強いところです。サンプルは無名関数ですが無論、変数にして呼び出すことも可能です。

Sample4

 // ==UserScript==
// @include http://m.hatena.ne.jp
// ==/UserScript==

message = document.getElementsByClassName("message-title")[0];
message.onclick = function(){ alert(Hello World!!); }

message.addEventListener("click",eventHandle,"true");


function eventHandle(){
alert("");
}

このようにしても警告表示を出すことが出来ます。

しかしながらこれでは0番目の配列の要素しか評価されず結果的に一番上のリンクにしかアラート関数が行き渡りません、ですのでclass配列を全て回し関数に渡すようにしてやります。

Sample5

 // ==UserScript==
// @include http://m.hatena.ne.jp
// ==/UserScript==

messageLength = document.getElementsByClassName("message-title").length;

for(i=0;i<messageLength;i++){
document.getElementsByClassName("message-title")[i].addEventListener("click",eventHandle,"true");
}

function eventHandle(){
alert("50個ちゃんとアラート表示されます");
}

 

具体的な説明として、配列の個数はdocument.getElements("class").lengthで 取得ができます。for文で配列は0から始まりますのでi=0と指定して配列長さを格納したmessageLength(今回は50個)より値が下の場合関数を作るという処理をします。これで50件全部のリンクにはクリックした時にアラートを出すというイベントを全て作成したという事になります。

 

イベントハンドラと具体的な関数の製作の説明は今回はここまでにしたいと思います。次回からは具体的にどのような感じで製作すれば便利にサイトを扱えるようになるかについて説明していきたいと思います。

はてなブログでpreタグ中でソースを書くときの改行とShiftの使い分け

preタグ中での改行でpre増産を防ぐ(見たまま編集)

ついこの前まで、HTML編集で<pre>タグを書いておき

見たまま編集で<pre>中にソースを書いて改行すると<pre>が改行した分増産されてしまう問題に頭を抱えていました。

結果HTML編集ですべてコードを書き、そしてタグを全部実体参照に置き換えたりしていたのですが、早い話Shiftキーを押しながらEnterを押せば<pre>中で改行できたんですね。

はてなブログ本体の仕様についてはあまり読む時間がないので自分の見過ごしかもしれませんが、割と便利です。

<pre>中で実際にTABが使えると嬉しいですよね。

まだまだ<pre>の仕様外のバグも存在しています。

早いことバグが減りHTML5のタグに対応してほしいものです<svg>や<canvas>等

HTML5のタグ挿入で公開したあとHTML5のタグが消えてしまうのも今のところ仕様です。

JavaScriptでgreasemonkeyを作成する方法2

DOMについて理解する

前回記事:http://yatagarasu0495.hatenablog.jp/entry/2012/02/26/210834

前回は具体的なgreasemonkeyについての記述方法を紹介しましたが、今回は実際にサイトで表示されてあるコンテンツを書き換えていこうと思います。

DOMについて

DOM(Document Object Model)について簡易的に説明すると一種のデータの位置関係を示すツリー構造と言えます。

JavaScriptでDOMについては知らなくても以下の記述を見た方はいると思います。

Sample1

 document.getElementById("sample");
document.getElementsByClassName("sample");
document.getElementsByTagName("p");
document.getElementsByName("sample"); 

基本的にid名及びclass名等から要素を選出して動的に操作を加えるのに使います。

これが簡易的なgreasemonkeyの要素だと言えます。

まずこのDOMに関してのSample1のような書き方が分かったうえでgreasemonkeyは始めて扱うことができます。

ではどうやってサイトのコンテンツを書き換えるのかについて考えてみます。

 

Firebugを使い既存のタグのclass名やid名を取得しつつ動的に変化を加える

FirebugJavaScriptデバッグにかかせないアドオンの一つですが、他にも様々な機能があります。

  • 各要素のid名やclass名の取得が容易
  • DOMタブより変数の値を任意の物に置き換えられる
  • XPATHが取得できる

などがあります。他にも便利な機能はありますが、詳しくはFirebugを実際に使ってみて確かめてください。

今回は一番上のid名やclass名取得が重要となります。

XPATHで動的に変化を加えるのはJavaScriptの範囲では入門、初級を超えるので今回は省きます。

Firebugを使い実際にid名やclass名が取得出来るようになった所で

はてなメッセージを実際にgreasemonkeyで改装していきます。

はてなメッセージは見た目もシンプルでgreasemonkeyの操作がしやすい

Sample2

 <a href="/"><img alt="" src="/images/header-logo.png" class="service-logo"></a>

//http://m.hatena.ne.jp/images/header-logo.png 

Sample2のソースは、はてなメッセージのTOPの画像にあたるものです。

実際にFirebugをonにして画像の上で右クリックしてFirebugで要素を調査してみましょう。調査するとソース画面が現れますがドラッグされている場所が該当する部分です。

そしてこの画像を別の画像に置き換えるという処理をやってみようと思います。

行う事は次の通り

  • class名及びid名を取得する
  • getElementを使い要素を指定する
  • 動的に書き換える

順序はこのようになります。

Sample3

 //<a href="/"><img alt="" src="/images/header-logo.png" class="service-logo"></a>

// class名 : service-logo
// はてなmessageTOP画像をはてなfotolifeTop画像に変える

hatenaImage = document.getElementsClassName("service-logo")[0];
hatenaImage.src = "http://f.hatena.ne.jp/images/logo-hatena.gif"; 

基本これだけです。

Demo

実際に書き変わりましたね。

 

DOMをあまり使っていない人に混合しがちな事をあげると

  • id名はhtml中に一つしか存在しないので配列は存在せず単体で取り出せる
  • class名はhtml中に何度も使えるため配列として保存され有限的に保管される

この二点です、getElementByIdを使った事が多い方にとってClass名の後ろに付く配列の[0]は斬新な書き方に見えるのではないでしょうか!?

class名は複数利用できるので配列を抜かしてしまうと全部の要素に適応される気もしますが実際は上手く動作しないので単体で使用するようにしましょう。

基本的には書き換えはこのパターンの繰り返しです。

greasemonkeyを扱うにあたってDOMは重要な概念となってきます。

DOMを深く理解した上で改めてgreasemonkeyについて扱うとわかり易いかもしれません。

今回は簡単な書き換えでしたが次回からは複雑なpatternを実装していこうと思います。

(CSSだけの書き換えはgreasemonkeyの勤めではないという事も覚えておきましょう)