データの差分を確認できるjavascriptライブラリMergely

案件によっては、納品時にソースといっしょに仕様書や差分情報も提出することがあります。
ただ、差異があまりに多い場合は、ワードやエクセル、パワーポイントなどで書類を作るのが本当にしんどいしナンセンスすぎる!
技術は進化しているのに、WEB屋さんで一般的に受注できる案件ではtracやsvnを導入できないケースがほんと多いな…
そんなわけで、ブラウザ上でデータの差分を確認できるMergelyで解決できないか導入してみました。

Mergelyはもともとオンラインサービスなのですが、javascriptのオープンソースライブラリ「Mergely Javascript Library」もリリースされています。

納品データとなれば、不特定多数の目に触れないよう慎重に取り扱うため、オンラインサービスでの共有は断念。
今回は、このライブラリをつかってローカル環境で差分を見られるようにするまでのチュートリアルです。

Mergelyライブラリ設置デモページ

Mergely動作要件

Mergely 用のjavascript、cssのほか、CodeMirrorjQueryも必要です。
対応ブラウザは、ざっくりいうとモダンブラウザ以上のものです。

  • Internet Exporer 9以上
  • Chrome どのバージョンでもOK
  • Firefox 2以上
  • Safari 3以上
  • Opera 9以上

ライブラリをダウンロード

まず、Mergelyライブラリページから最新版をダウンロードします。
2012年3月20日時点ではVersion 3.2がでていたので、これをダウンロードしました。

ダウンロードしたmergely-3.2.zipを展開すると、リファレンスとサンプルソース、コアとなるソースが入っています。

libディレクトリの中には、MergelyのソースだけでなくCodeMirrorのソースもセットで入れてくれています。
サンプルソースではjQueryをオンラインで外部参照しているため、jQueryは初期のlibには入っていません。
外部参照したくない場合は、jQueryも本家からダウンロードしてきてlibディレクトリに追加しておきます。

デモページはこんな構成にしました。

  • /lib/
    • /lib/codemirror.css:CodeMirrorデータ(スタイルシート)
    • /lib/codemirror.min.js:CodeMirrorデータ(javascript)
    • /lib/jquery-1.9.1.min.js:jQueryデータ
    • /lib/mergely.css:Mergelyデータ(スタイルシート)
    • /lib/mergely.min.js:Mergelyデータ(javascript)
  • /index.html:差分情報を表示するhtml
  • /custom.css:自作のヘッダ部分のスタイルを定義
  • /lhs.txt:元のデータとして左側へ読み込む情報
  • rhs.txt:新しいデータとして左側へ読み込む情報

Mergely Javascript Libraryを適用

index.htmlでライブラリを使うための設定をしていきます。

まず、<head>へライブラリ用のデータを読み込みます。jQuery、CodeMirrorの次にMergelyの順です。

<link rel="stylesheet" type="text/css" href="./lib/codemirror.css">
<link rel="stylesheet" type="text/css" href="./lib/mergely.css">
<link rel="stylesheet" type="text/css" href="./custom.css">
<script src="./lib/jquery-1.9.1.min.js"></script>
<script src="./lib/codemirror.min.js"></script>
<script src="./lib/mergely.min.js"></script>

次にMergelyを設定します。デモではhtmlの<head>へ<script>で記載しています。

$(function () {
	$('#compare').mergely({
		cmsettings: {
			readOnly: false, // フィールドの編集許可。falseで編集OK、trueで編集不可。
			lineWrapping: true // フィールドの端で折り返すかどうか。初期値はfalse。trueなら右端で折り返すので横スクロールバーが出ない。
		},
	});
});

<body>には、上記でMergelyの設定対象になっている<div id=”compare”></div>を必ず置きます。
サンプルでは#compareと命名していますが、紐付けがきちんとできていれば任意の要素を指定できます。

<body>
	<div id="mergely-resizer">
		<div id="compare"></div>
	</div>
</body>

続いて、差分を確認したいデータを左右のフィールドへ定義します。

$(function () {
	$('#compare').mergely({
		cmsettings: {
			readOnly: false,
			lineWrapping: true
		},
	});
	// 左のフィールドへlhs.txtを読み込む
	$.ajax({
		type: 'GET', async: true, dataType: 'text',
		url: 'lhs.txt',
		success: function (response) {
			$('#compare').mergely('lhs', response);
		}
	});
	// 右のフィールドへrhs.txtを読み込む
	$.ajax({
		type: 'GET', async: true, dataType: 'text',
		url: 'rhs.txt',
		success: function (response) {
			$('#compare').mergely('rhs', response);
		}
	});
});

上記でハイライトした部分はほとんどMergely用の書式ではなくjQueryのajaxで外部ファイルを読み込む設定です。
Mergelyのフィールドへデータを反映させるための設定は、success内の処理にあたります。

$.ajax({
	type: 'GET', async: true, dataType: 'text',
	url: 'rhs.txt', // 読み込みたい外部ファイルまでのパス
	success: function (response) {
		/*
		無事に指定した外部ファイルを読み込めた場合に実行する処理をここに書く。
		変数responseには読み込んだ外部ファイルの内容が格納されています
		*/
		$('#compare').mergely('rhs', response);
	}
});

ちなみに、外部ファイルの読み込みではなくフィールドの内容を直書きする場合はこう書きます。

$('#compare').mergely({
	lhs: function(setValue) {
		setValue('編集前の\nテキストです'); // 左側に反映するテキスト
	},
	rhs: function(setValue) {
		setValue('編集後の\nテキストです'); // 右側に反映するテキスト
	},
});

オリジナルのヘッダを追加してみる

デフォルトでは、画面いっぱいにdiff情報のフィールドだけが表示されているだけだったので
オリジナルのヘッダを追加し、ヘッダの大きさを差し引いだサイズでdiffフィールドを画面いっぱいに表示するよう改造してみました。

$('#compare').mergely({
	cmsettings: { readOnly: false, lineWrapping: true },
	resized: function(){
		/*
		ここに、リサイズイベントで実行したい処理を書きます。
		サイズを指定する式は、mergely.jsでautoresizeの処理をしているところと
		同様に指定しました。
		*/
		var w =   $('#compare').width();
		$('#header').width(w);
		$('#header .lhs, #header .rhs').width((w - 28) / 2);
		
		var h = jQuery(window).height() - $('#header').height() - 8 - 8;
		var content_height = h;
		$('#compare').find('.mergely-column, .mergely-canvas, .mergely-margin, .mergely-column textarea, .CodeMirror-scroll, .cm-s-default').css({ 'height': content_height + 'px' });
		$('#compare').find('.mergely-canvas').css({ 'height': content_height + 'px' });
		$('#compare').css({ 'height': h + 'px' });
	},
});

ヘッダ部分のHTMLはこんな感じ。ヘッダのスタイルはcustom.cssで指定しています。

<body>
	<div id="mergely-resizer">
		<div id="header">
			<span class="headline"><strong class="current">タイトル</strong></span>
			<div class="lhs half">
				<span class="subHeadline">元のデータ</span>
				<a class="button" href="lhs.txt">PREVIEW</a>
			</div>
			<span class="arrow">⇒</span>
			<div class="rhs half">
				<span class="subHeadline">新しいデータ</span>
				<a class="button" href="rhs.txt">PREVIEW</a>
			</div>
		</div>
		<div id="compare"></div>
	</div>
</body>

実際に試してみて…

私の脳ミソが足りないのか、本家のリファレンスを手がかりにオプションを設定しようとすると迷走しました…
javascriptのソースコードをある程度解読できる方なら
リファレンスとにらめっこするよりも、実際のソースmergely.jsから仕組みを読み解いたほうが手っ取り早いかもしれません。

関連記事

Pocket