Google Analyticsをスマートにインストール

前回のエントリーでprototype.jsを使ったサイト名.jsをおすすめしました。
http://d.hatena.ne.jp/eichi-m/20070818

そのサイト名.jsを使ってanalyticsのjsファイルを動的に読み込ませて、html側にjavascriptを書かずにインストールをします。

まず必要な事を挙げてみます。

  • google analyticsのjsファイルを読み込む
  • ページがロードされたらurchinTracker()関数を実行する

ちなみにGoogle Analyticsのリファレンスでは</body>までの間に下記のjavascriptコードを貼付けろと書かれていますので、下記のコードを貼付けた場合と同じ事ができるようにサイト名オブジェクトにメソッドを記述します。

<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
  _uacct="UA-xxxx-x";
  urchinTracker();
</script>

外部javascriptを動的にロードするメソッド

まず、html側にanalyticsに関するjavascriptを記述しないということはサイト名オブジェクトから動的にanalyticsのjsファイルを読み込めるようにする必要があります。
そこで、オブジェクトにloadJSというメソッドを作成します。

loadJS : function(url) {
    var head = document.getElementsByTagName('head')[0];
    var addTag = document.createElement('script');
    addTag.type = 'text/javascript';
    addTag.src = url;
    head.appendChild(addTag);
}

このメソッドはhtmlのheadをオブジェクトとして取得、取得したheadにscriptエレメントを追加するメソッドです。
引数に読み込むスクリプトのURLを指定します。

関数が読み込まれているかチェックするためのメソッド

次に関数が読み込まれているか(実行可能か)をチェックするためのメソッドを作成します。
これは、動的にスクリプトを読み込んだ場合において読み込みが完了する前に関数を実行してエラーを引き起こさないようにするためのものです。
このメソッドを使って読み込み完了ならば実行、読み込みが完了していなければwaitという動きを実現します。

isLoaded : function(load) {
    try {
        eval('var type = typeof(' +load+ ')');
        if(type.match(/^function$/i)) return true;
    } catch(e) {
        return false;
    }
    return false;
}

引数には関数名(string)を渡します。。
このメソッドは渡された関数名をtypeof()でチェックし、タイプがfunctionならばtrueを返しそれ以外はfalseを返します。
このメソッドを拡張することで、objectのチェックや複数の関数をチェックすることも可能です。

urchinTracker()を実行するメソッド

Analyticsのロギングを実行する関数であるurchinTracker()を実行するためのメソッドを作成します。

analytics : function() {
    if(!this.isLoaded('urchinTracker')) {
        // まだ読み込みが完了していなければ120ミリ秒後に再度試行
        setTimeout(function(){ this.analytics(); }.bind(this), 120);
        return false;
    }
    // ロギング実行
    _uacct = 'UA-xxxxxxx';
    urchinTracker();
}

まず、上で作成した関数が読み込み済みかどうかをチェックするメソッドでチェックしています。
まだ読み込みが完了していなければ、120ミリ秒待ってから再帰的に自メソッドを呼び出して再度実行を試みます。
読み込みが完了していれば、AnalyticsのIDを定義した後にurchinTracker()を実行します。

initializeでwindowが読み込まれたら自動実行する

最後にprototypeのClassで生成したオブジェクトの拡張機能initializeを使ってページをロードした際に一連のメソッドを自動実行させます。

initialize : function() {
    // 動的にファイルをロード
    this.loadJS('http://www.google-analytics.com/urchin.js');
    // windowがonloadされたらロギング実行
    Event.observe(window, 'load', function(){ this.analytics(); }.bind(this));
}

以上で完了です。
この方法を使えば、各ページのhtmlにanalyticsのjavascriptを記述することなくサイト名.jsさえ読み込めばanalyticsのロギングを実行してくれます。

最後に一連のメソッドを全部まとめておきます。

var hogeClass = Class.create();
hogeClass.prototype = {

    initialize : function() {
        this.loadJS('http://www.google-analytics.com/urchin.js');
        Event.observe(window, 'load', function(){ this.analytics(); }.bind(this));
    },

    loadJS : function(url) {
        var head = document.getElementsByTagName('head')[0];
        var addTag = document.createElement('script');
        addTag.type = 'text/javascript';
        addTag.src = url;
        head.appendChild(addTag);
    },

    isLoaded : function(load) {
        try {
            eval('var type = typeof(' +load+ ')');
            if(type.match(/^function$/i)) return true;
        } catch(e) {
            return false;
        }
        return false;
    },

    analytics : function() {
        if(!this.isLoaded('urchinTracker')) {
            setTimeout(function(){ this.analytics(); }.bind(this), 120);
            return false;
        }
        _uacct = 'UA-xxxxxxx';
        urchinTracker();
    }
}
var hoge = new hogeClass();


動的なスクリプト読み込みと読み込み完了チェックのメソッドはAnalyticsだけではなく、その他様々な用途があると思います。
htmlに書くscriptタグを少なくすることができるので、当然htmlがすっきりしてテンプレートの管理も楽になります。

サイト名.jsのススメ

最近では多くのサイトがprototype.jsを読み込んでいますね。
どのサイトでも同じjsなのにサイトごとにキャッシュさせられるのはいかがなものかと思うので、いっそのこと下のようなURLで読み込めば常に最新のprototype.jsが提供されるといったサービスにしてくれたら良いのに。

<script src="http://prototypejs.com/prototype.js" type="text/javascript"></script>

などと思ってみたりするのですが、それはとりあえずいいとしてこのエントリーは「サイト名.jsのススメ」
です。

javascriptフレームワークフレームワークらしく使う

prototypeを利用しているサイトのソースを覗かせてもらうと、prototypeを単にライブラリとしてしか使っていないサイトが結構あります。
例を挙げるとこんな具合。

<html>
<head>
<script src="prototype.js" type="text/javascript"></script>
<script>
  function hoge() {
    Event.observe('buttonA', 'click', hogehogefunction);
  }
  Event.observe(window, 'load', hoge);
</script>
<script src="***.js" type="text/javascript"></script>
<script src="****.js" type="text/javascript"></script>
</head>

さらに別のjsファイルやhead、body内にツラツラとfunctionが書かれていたりするわけです。
それがダメだという訳じゃないけれど、管理のしやすさや名前空間を考えるとprototypeのclassを使って1つのオブジェクトにすべておさめてカプセル化してしまったほうが良いのではないかと思います。
ソースコード(HTMLやjs)が煩雑にならずに済むというメリットがあるほか、htmlが整理整頓されるということは検索エンジンのクローラに対しても多少印象が良くなるのではと思います。
そこでサイト名.jsのススメです。

サイト名.jsの記述方法

例えばhoge.comというサイトで使用するjavascript(hoge.js)を記述する場合。

/**
 * file: hoge.js
 * class: hogeClass
 * instance: hoge
 */

// クラス生成
var hogeClass = Class.create();

// メソッドの実装
hogeClass.prototype = {

    initialize : function() {
      // インスタンス生成と同時に初期化やメソッドの呼び出しをします
    },

    /**
     * 共通で利用できるメソッド
     */
    commonMethod_1 : function() {
      // メソッド間で共有するメソッド1
    },

    commonMethod_2 : function() {
      // メソッド間で共有するメソッド2
    },

    /**
     * トップページで使用するメソッド
     */
    topMethod_1 : function() {
      // トップページで利用するメソッド1
    }

    .......各ページごとのメソッド
}

// インスタンス生成
var hoge = new hogeClass();

といった形で記述します。

始めにprototypeのClass.create()を使ってhogeClassを生成します。
次に生成したクラスにメソッドを実装しています。
メソッドの記述方法は、initialize、汎用メソッド、各ページごとのメソッドという形。
initializeはprototype.jsで生成したクラスのコンストラクタで、インスタンス生成と同時に実行されるメソッドです。
ちなみに例ではcommonMethod_1というようなメソッド名にしていますが、これは機能に適したネーミングが良いでしょう。
また、ページごとに利用するメソッド名にはtopMethodNameというような形で接頭辞にページ(コンテンツ)名を付けておくと良いと思います。
最後にhogeClassの実体になるインスタンスhogeをnewで生成していますので、jsファイルが読み込まれた時点で各メソッドを持ったhogeオブジェクトが存在していることになります。

使い方は簡単

prototype.jshoge.jsを読み込みます。
例えばアンカーのonclickでtopMethod_1を実行したい場合は下のようにhtmlを書くことになります。

<a href="javascript:void(0);" onclick="hoge.topMethod_1();">クリックでメソッド実行</a>

また、メソッド間でお互いを実行する場合は当たり前ですがthis.メソッド名()で呼び出します。

サイト内で使用するjavascriptを1枚のjsファイルに記述し、常に“サイト名.メソッド名()”という形で実行するというルールを作ることでjavascriptの管理をスマートにします。

initializeに関するTips

コンストラクタを実装するinitialize等のオブジェクトの拡張機能を使わないのであればclassを使わずに単なるオブジェクトとして定義しておくだけでも良さそうな気もしますが、中でもinitializeは大変便利です。

例えばwindowをonloadした時に常に実行したいfunctionがある場合。

// メソッドの実装
hogeClass.prototype = {

    initialize : function() {
      this.message = 'ページが読み込まれました'; // メッセージ
      this.onloadMethod(); // インスタンス生成時に実行
    },

    onloadMethod : function() {
      // windowにイベントをセット
      Event.observe(window, 'load', function() {
        alert(this.message); // onloadでアラート表示
      }.bind(this));
    }
}

このようにしておくとインスタンスを生成した際に自動的にwindowのonloadイベントにonloadMethodをセットすることができます。

私の場合はサイトを構築する際にgoogle analyticsを導入することが多いので、initializeでanalyticsのjsファイル(http://www.google-analytics.com/urchin.js)を動的に読み込んだ上analyticsの関数urchinTracker()を実行するという使い方をしています。
この方法を使えばhtmlにanalyticsのjavascriptを書かなくて済むためhtmlとjavascriptをきれいに分離できます。
何よりもhoge.jsさえ読み込んでおけば、各ページのhtmlにいちいちanalyticsのjavascriptを書かなくてもanalyticsを呼んでくれるのが良いです。

せっかくファイルサイズの大きい多機能なprototype.jsを読み込んで使うのだから、そのフレームワークとしての機能をうまく使ってスマートにjavascriptを書くことをおすすめします。

次回以降のエントリーでサイト名.jsからさらに外部jsファイルを読み込む方法や上で述べたサイト名.jsでanalyticsをインストールする方法を説明したいと思います。

日本的インターネッツ

twitterってどこいった?ってくらいもう話題に上らなくなってきた。
わかってはいたけれど、海の向こうで流行ってるっぽいっていうのを聞いて一瞬だけ消費しまくるっていうのが実に日本的だなーと思う。
ビリーズブートキャンプにも同じものを感じる。
でも、ビリーズブートキャンプは企画商品だから一瞬だけでも売れれば良いけどね。

そんなわけで、最近のwebサービスを独断と偏見でもって分析してみることにする。

twitter

海の向こうで流行ってるらしいと聞きつけた一部が「流行の最先端に乗ったぜー!ナウイぜー!」と電波発信。
でも釣られた人が増えると流行の最先端風味が薄れてつまらなくなって離れる。
つまるところ、サービスの本質に利用価値を見出していたわけではなくて最先端風味を味わいたかっただけ。
例えるとこんな感じ?
六本木ヒルズが出来たと聞いて用は無いけれどとりあえず行ってみようと思って来ちゃいました。

mixi

これは匿名性を排除した閉鎖的なインターネッツってところが新鮮だったんじゃないかな。
生まれるずっと前にペリーが来て開国していたけど、今日から鎖国です!くらいの新鮮っぷりがもしかしたらあったかもしれない。
パソコン通信の頃に時代回帰しただけでしょ、と言う人もいるけど今のネットユーザーのほとんどがパソ通時代を知らないはず。
そして、その鎖国インターネッツの使われ方を見るとまたこれが結構日本的だったりする。
隣近所のオバチャンによる井戸端会議サークルのようで、集まる人数はほぼ一定。
そのうち集まる事に疲れたオバチャンは脱落するが、帳尻を合わせるかのように人員が補充されている。
気が付くと、メンバーはすっかり入れ替わり世代交代をしている。
そして鎖国中とはいえ国際結婚を推奨、絶賛受入れ中なので鎖国の意味がなくなりつつある。
外国人犯罪も多発中。

youtube

動画を手軽にしたyoutube
技術的にはさほど新しいものではなかったけれど、かつてそのインフラを無料で開放できるところは無かった。
これも本国とは使われ方が違うように思う。
まず日本人がyoutubeを見る動機になったのが著作権に触れるような動画を無料で見ることだったように思う。
でもそれを規制された途端に距離を置くようになる。
日本人は自分撮りをアップロードし合って盛り上がることは無いし、ましてやyoutubeだけのために個人で番組を作成してしまうような人もいない。
たまに海外のおもしろ投稿動画がblogのネタにされるくらい。
つまるところ、健全な動画共有サイトを作ろうとすると酷いことになる。
まだyoutubeはマシだけど、sony動画共有サイトって…

secondlife

プレイしてみたけど、正直言って日本人には合わないと思った。
日本人はバーチャルな世界にリアリティを求めていないように思う。
どちらかと言うと、バーチャルな世界だからこそ見れるビジュアルとアクションを求める傾向じゃないかな。
だから日本人はSLの中で外国の人が作らないような着ぐるみを着ていたりする。
パーティを組んでこれからモンスター退治に行くぜー!という方が恐らく合っているんだろうと思う。
なので、これからsecondlifeくるぜー!と鼻息荒く入れ込んでる企業はあさっての方向を向いている可能性がありますよーと勝手なことを言ってみる。


まとめると、海外で流行ってるらしいものをそのまま持ってきても一瞬は盛り上がるかもしれないが日本人には合わないものが多い。
ビリーズブートキャンプのように一瞬の盛り上がりで勝負をつけることができれば良いけれど、webサービスでそれは難しい。
ポイントとしてはこんなところかな?
匿名性を排除することはネットの世界を狭めることに繋がりいずれユーザーは閉塞感を感じて離れていく。
またネットとリアルをより近づけようとすることもネットの世界を狭める事になり、いずれユーザーは閉塞感を感じて脱落する。
さらに、本来は健全であるべきだろうけれどアンダーグラウンドな部分を完全に排除することもネットの世界が狭まったと感じてユーザーは離れていく。

ここまで考えると、日本でwebサービスを広めて長く続けるのはものすごく難しいことだとつくづく思う。
とはいえ、マネや劣化コピーじゃなくて日本人が日本人のために日本的なサービス作ることはきっとできるはずだろうと思っています。
今のところ2chとニコニコは日本的な線をいってるんじゃないかと。

さて、SAMURAIかHARAKIRIかKAMIKAZEか…

CSSハックとかweb標準とか

web標準
わかるよ、わかるけど、もうそういう単語にすがってwebの先端気取りになるのをやめにしないか。
web2.0もみんな大好きだったね。
考え方や捉え方としての単語なら大歓迎だし、それについて議論するのは良い事だと思う。
でも実際は生産性に欠けるんじゃないかと感じてるし、なんとなくwebのスピードが落ちたように感じてる。

あえて枠にハマる事でできるクリエイティブもあると思うけど、枠にハマらず考えた事をどんどん形にしていったほうがクリエイティビティに富んだwebになるんじゃないかと。
だからハックは邪道だとか、strictなコードじゃないとダメだとかどうでもいい気がしてきた。

本当にstrictなコードを書かないと困るエンドユーザーがどれだけいるの?
ハックしてると困るユーザーがどれだけいるの?
品質として求められるというのはわかるけど、使うのはエンドユーザー。
エンドユーザーの視点から見ると、strictなソースじゃなくてもちゃんとブラウザで表示できればいいわけで。

だからもしすんなりstrictなコードが書けるなら書けばいいと思うけど、それで生産性が落ちるくらいならどんどんハックすればいいと思う。
って、ここまで書いただけで終わらせるのもアレなので私の場合のCSSコーディング方法を参考までに。

  • 基本的に、XML宣言あり(IE6を除くモダンブラウザで標準準拠モード)でコーディング
  • CSSは共通CSSと各コンテンツCSSに分けて書いてimport
  • コンテンツ同士で共通するスタイルがあってもコンテンツ(ページ)別に分けて書く
  • まずはwindows firefoxを基準にコーディング
  • firefoxでのコーディングが終了したら各CSSファイルの最後にハックを書く

今まで色々と試行錯誤を繰り返したが、一番速く楽にコーディングする方法としては現在のところXML宣言ありでIE6に対してのみwidthとheightの調整をする形に落ち着いています。
CSSは同じスタイルがあるとどうしても共通classにしたくなるが、グッとこらえてコンテンツ別のスタイルとして書く。
レンダンリングはさほどエレガントではないけれど、一番標準的なfirefoxを基準にコーディングしています。
ちなみに、IE6以後のブラウザしかターゲットにしません。
IE5とか使ってる人もいるとは思うけど、もうそんな古いブラウザに対して提供できる新しいサービスを作ることは難しすぎるため。

ソースの例

/**
 * common.css(共通CSS)
 */

/* エレメントのスタイル */
body {}
div {}
a {}
...etc

/* ベースレイアウト */
#header {}
#container {}
#footer {}
#left {}
#center {}
#right {}

/* header内のコンテンツスタイル */
#header h1 {}
#header p {}

/* footer内のコンテンツスタイル */
#footer ul {}
#footer ul li {}
#footer p {}

/* left内のコンテンツスタイル */
#left ul.nav {}
#left ul.nav li {}
...etc

/* right内のコンテンツスタイル */
#right ol.hogelist {}
#right ol.hogelist li {}
...etc

/**
 * メインコンテンツになるcenter内のスタイルはページごとに別ファイルで書く
 * ページごとにコンテンツ名classをつける
 * 例)#center.toppage {}
 */

/**
 * hack@ie7
 * font-sizeをfirefoxより10%ほど下げる
 * line-heightを140%くらいに
 * letter-spacingを0.1emくらいに
 */
*+html body {}

/**
 * hack@ie6
 * font-sizeをfirefoxより10%ほど下げる
 * line-heightを140%くらいに
 * letter-spacingを0.1emくらいに
 * paddingとwidth/heightを同時に指定してあるものはwidth/heightをpadding+width/heightに修正
 */
* html body {}
* html body #left ul.nav {
	例)padding: 5px; → padding: 5px;
	例)width: 200px; → width: 210px;
}

感じとしてはこんな形でやるのが今のところ一番効率が良いです。
firefoxでのコーディングが終わった後にIE6で表示すると「うわっ」と思いますが、width/heightを検索して同時にpaddingが指定してあるものは下にコピーし修正で意外と早く済みます。

今まで試行した中で一番効率の悪い方法は、都度色々なブラウザで表示確認をしながらコーディングする方法。
なるべくハックしないように書こうとするとやってしまいがちだけど、一つのブラウザで表示が整っていないために変更を加えるとまた違うブラウザで表示が崩れる、という効率の悪いループを繰り返すハメに。

handsup公開


約1ヶ月をかけてデザインからプログラミングまでを行い、作っていたサイトを公開。

handsup - ウェブ制作×フリーランスという選択
http://handsup.jp/

コミュニティサイト等で制作依頼の投稿があったりすると多くの場合が荒れてしまうのを見ていて、そういうことがもっと軽くできても良いんじゃないかな?と思い作ったサイトで、求人ではなく案件単位で制作の依頼、制作受託をするためのサイト。

他にもSOHOマッチングサイトと呼ばれるようなものは色々あるけれど、サイトが案件に介入して中間マージンを得るものやシステム利用料がかかるサイトが多い。
投稿の信頼度を確保するためには利用料のようなものを徴収したほうが良いのかもしれないけれど、ただ純粋に案件のリレーションができる場の提供をしたいと思い今後も一切利用料等は得ない考えで。

SNSのような閉鎖的なコミュニティでは質問スレもたてずらいと思い、フォーラムはウェブ制作に関わる質問を気軽に出来るよう、登録無しの匿名にて投稿が可能。
そういう意味では馴れ合わない系。
昔の「ネチケットを守って投稿してね!」みたいな感じのパブリックな掲示板は良かったなー、とか思ったりするわけです。

今回、主な機能として実装したもの

  • 募集(通常選考・コンペ形式)
  • コメント(プロジェクトに関する質問等)
  • 公開資料アップロード・ダウンロード(応募要綱や企画書等のクリエイター向け公開資料)
  • メッセージ(特定ユーザーへのメッセージ)
  • ファイル送信(特定クリエイターorクライアントへファイル送信)
  • 評価

ひとまずこのくらいあれば良いかなーという感じ。
あまり富豪的に機能を付けても煩雑になるだけなので。
煩雑といえば、フォームの類をインラインウィンドウに収めたら随分とスッキリした。

フリーランスでウェブ制作をしているクリエイターと仕事を繋げる、もしくはもっと軽く制作依頼をしたい方にとって有益なサイトになれば良いなと思います。

まずはテスト投稿やエントリーのテストをして色々試してもらいたいと思います。