JavascriptでYahoo!などのタグマネージャに渡すためのイベントを発生させる

## ちょっと賢いリマーケティング

タグマネージャを使ってちょっと賢い、ちょっと効率的なリマーケティングをやりたい。
多くのアカウントで共通して使える、お手軽なアドバンスト・リマーケティングの実装法を紹介する。

ディスプレイ広告の世界、やれ認知だ、アトリビューションだなどといっても、所詮リマーケティング広告大全盛である。
その運用の実際はとりあえず当該サイトのどこかのページを閲覧した（無条件でリマーケティングタグを読み込んだ）だけで
リマーケティングをするということが多い。

中には**リーセンシー（直近○日以内に閲覧した）**や**閲覧したページの種類（トップページ or 詳細ページなど）**で
入札の重みを変える場合もある。これらは管理画面上の設定で可能な絞り込みの方法である。

ところが**2ページ以上閲覧した**だとか、**120秒以上閲覧した**だとか、より深くページを閲覧した**特定の行動**に対してリマーケティングを行うのは管理画面上の設定だけでは不可能なことが多い。それをJavascriptの機能を使って実現する。

## メカニズム

今回はタグマネージャにイベントを渡し、タグマネージャ側で

    特定のイベントが発生 → タグを発火

という設定（タグ発火のルール）をすることで実装するケースを想定する。

Cookieを使うことになるので、Cookieを読み書きするライブラリを使う。
さらに特定の行動が発生したら**オリジナルのイベントを発生させる**関数を用意する。

```js
function fe(name, element) {
	element = element || window;
	if (document.createEvent) {
		// IE以外
		var evt = document.createEvent('HTMLEvents');
		evt.initEvent(name, true, true); // event type, bubbling, cancelable
		return element.dispatchEvent(evt);
	} else {
		// IE8以前
		var evt = document.createEventObject();
		return element.fireEvent('on'+name, evt);
	}
}
```

最後にタグマネージャ側でそのイベント名を拾い、それをトリガーにして特定の
リマーケティングタグを出力する（こちらは管理画面の設定）


`document.createEvent()`→`event.initEvent()`→`element.dispatchEvent()`という一連の流れになる。

IE8以前は少し異なる。

## まとめると

### IE9以降のみ対応でいいなら

```js
/*
 * ライブラリ
 */
// cookie処理用ライブラリ
var cookie = {
	set: function(cname, cvalue, exdays) {
		var d = new Date();
		d.setTime(d.getTime() + (exdays*24*60*60*1000));
		var expires = "expires="+d.toUTCString();
		document.cookie = cname + "=" + cvalue + "; " + expires;
	},
	get: function(cname) {
		var name = cname + "=";
		var ca = document.cookie.split(';');
		for(var i = 0; i < ca.length; i++) {
			var c = ca[i];
			while (c.charAt(0) == ' ') {
				c = c.substring(1);
			}
			if (c.indexOf(name) == 0) {
				return c.substring(name.length, c.length);
			}
		}
		return "";
	}
};

// 独自イベントの生成から発火まで
function fe(name, element) {
	element = element || window;
	var evt = document.createEvent('HTMLEvents');
	evt.initEvent(name, true, true); // event type, bubbling, cancelable
	return element.dispatchEvent(evt);
}

/*
 * 実行
 */

// 1. 2PV以上でイベントを発生させる（タグマネージャにイベントを送信）
document.addEventListener('DOMContentLoaded', function(){
	if(navigator.cookieEnabled == false){
		return;
	}

	// PV数の閾値（これより多い場合にイベント発火）
	var threshold = 1;

	// cookieから累積PV数を取得
	var iPV = cookie.get('iPV') || 0;
	iPV = parseInt(iPV) + 1;
	cookie.set('iPV', iPV, 30);

	// PV数が規定より多い場合にイベント発火
	if (iPV > threshold) {
		fe('Session_2PV');
	}
});

// 2. 閲覧2分以上でイベントを発生させる（タグマネージャにイベントを送信）
document.addEventListener('DOMContentLoaded', function(){
	if(navigator.cookieEnabled == false){
		return;
	}

	// 秒数の閾値（これより長い場合にイベント発火）
	var threshold = 120;

	// cookieから訪問日時を取得
	var d = new Date();
	var timeFirst = cookie.get('timeFirst') || d.getTime();

	// cookie書き込み（セッション限りのcookieなので期限を設定しない）
	document.cookie = 'timeFirst=' + timeFirst + ';path=/';

	// 発火期限
	var limit = timeFirst + threshold * 1000 - d.getTime();

	if (limit > 0){
		window.setTimeout(function(){
			fe('Session_over2min');
		}, limit);
	}
});
```

- 前者は`window`オブジェクト（YTMでいうエレメントセレクタ）のイベント名（YTMのトリガー）「Session_2PV」
- 後者は`window`オブジェクト（YTMのエレメントセレクタ）のイベント名（YTMのトリガー）「Session_over2min」

### IE8以前対応の場合

```js
/*
 * ライブラリ
 */

// cookie処理用ライブラリ
var cookie = {
	set: function(cname, cvalue, exdays) {
		var d = new Date();
		d.setTime(d.getTime() + (exdays*24*60*60*1000));
		var expires = "expires="+d.toUTCString();
		document.cookie = cname + "=" + cvalue + "; " + expires;
	},
	get: function(cname) {
		var name = cname + "=";
		var ca = document.cookie.split(';');
		for(var i = 0; i < ca.length; i++) {
			var c = ca[i];
			while (c.charAt(0) == ' ') {
				c = c.substring(1);
			}
			if (c.indexOf(name) == 0) {
				return c.substring(name.length, c.length);
			}
		}
		return "";
	}
};

// ページのDOMツリー構築後に実行（要するにwindow.onload）
function ale(fn){
	if (window.addEventListener) {
		window.addEventListener('load', fn, false);
	} else if(window.attachEvent) {
		window.attachEvent('onload', fn);
	} else {
		window.onload = fn;
	}
}

// 独自イベントの生成から発火まで
function fe(name, element) {
	element = element || window;
	if (document.createEvent) {
		// IE以外
		var evt = document.createEvent('HTMLEvents');
		evt.initEvent(name, true, true); // event type, bubbling, cancelable
		return element.dispatchEvent(evt);
	} else {
		// IE8以前
		var evt = document.createEventObject();
		return element.fireEvent('on'+name, evt)
	}
}

/*
 * 実行
 */

// 1. 2PV以上でイベントを発生させる（タグマネージャにイベントを送信）
ale(function(){
	if(navigator.cookieEnabled == false){ return; }

	// PV数の閾値（これより多い場合にイベント発火）
	var threshold = 1;

	// cookieから累積PV数を取得
	var iPV = cookie.get('iPV') || 0;
	iPV = parseInt(iPV) + 1;
	cookie.set('iPV', iPV, 30);

	// PV数が規定より多い場合にイベント発火
	if (iPV > threshold) {
		fe('Session_2PV');
	}
});

// 2. 閲覧2分以上でイベントを発生させる（タグマネージャにイベントを送信）
ale(function(){
	if(navigator.cookieEnabled == false){ return; }

	// 秒数の閾値（これより長い場合にイベント発火）
	var threshold = 120;

	// cookieから訪問日時を取得
	var d = new Date();
	var timeFirst = cookie.get('timeFirst') || d.getTime();

	// cookie書き込み（セッション限りのcookieなので期限を設定しない）
	document.cookie = 'timeFirst=' + timeFirst + ';path=/';

	// 発火期限
	var limit = timeFirst + threshold * 1000 - d.getTime();

	if (limit > 0){
		window.setTimeout(function(){
			fe('Session_over2min');
		}, limit);
	}
});
```

## Javascriptの便利なライブラリ

- [JavascriptでYahoo!などのタグマネージャに渡すためのイベントを発生させる](http://qiita.com/gigamori/items/ec7542b19244c6776cd5)
- [Javascriptで正規分布の実装まとめ（乱数、累積分布関数など）](http://qiita.com/gigamori/items/e17e6f9faffb78822c56)
- [超簡単（手抜き？）cookie操作用のJavascript](http://qiita.com/gigamori/items/8a7d0cd29c05716bc2da)
- [超シンプルに、イベントハンドリング用の関数](http://qiita.com/gigamori/items/d0c5f5842671ec634f4a)
- [スマホのタップ対策済みのクリックイベントリスナ（スワイプやフリックは除外）](http://qiita.com/gigamori/items/5cdc91817564be66c2e6)