はじめてのwebサイト製作として、2つのtextareaの差分を色付けして表示する文章比較サイトを作りました。

f:id:KaneyHonest:20210314190616p:plain

目的

n予備校プログラミング入門コースを修了して何か作ってみようと思ったときに、n予備校時代にサンプルコードを写経して動かなかったときに使っていた文章比較サイトを改良してみようと思い作りました。

設計

「文章比較」とググってヒットするサイトは、見た限りでは2つのtextareaに文章を貼り付けたらボタンを押して下に色付きで差分が表示されるものでした。

そこでリアルタイム(ボタンなし)でtextarea内に直接差分を色付きで表示し、下には色付された行数と文字が表示されるものを作ろうと思いました。(textareaだけあれば行数表示はなくても十分使えるのでやめました)

まずは最初なのでhtml,css,javascriptだけで作ることにしました。

textareaに行数を表示する

こちらのライブラリーを使用することで左側に行数を表示できました。

github.com

文章を比較する



当初は上のツイートのように考えていたのですがうまく比較できず、こちらもライブラリーを見つけて使用することにしました。


github.com

そのまま使うと改行の際に↵が出るのと追加した部分だけ、または削除した部分だけ色付けになるように改変しました

    function diff_colorGreen(diffs) {
      var html = [];
      var pattern_amp = /&/g;
      var pattern_lt = /</g;
      var pattern_gt = />/g;
      var pattern_para = '↵';
      for (var x = 0; x < diffs.length; x++) {
        var op = diffs[x][0];    // Operation (insert, delete, equal)
        var data = diffs[x][1];  // Text of change.
        var text = data.replace(pattern_amp, '&amp;').replace(pattern_lt, '&lt;')
            .replace(pattern_gt, '&gt;').replace(pattern_para, '&para;<br>');
        switch (op) {
          case DIFF_INSERT:
            html[x] = '';
            break;
          case DIFF_DELETE:
            html[x] = '<span style="background:#43FF6B;">' + text + '</span>';
            break;
          case DIFF_EQUAL:
            html[x] = '<span>' + text + '</span>';
            break;
        }
      }
      return html.join('');
    };
    
    function diff_colorRed(diffs) {
      var html = [];
      var pattern_amp = /&/g;
      var pattern_lt = /</g;
      var pattern_gt = />/g;
      var pattern_para = '↵';
      for (var x = 0; x < diffs.length; x++) {
        var op = diffs[x][0];    // Operation (insert, delete, equal)
        var data = diffs[x][1];  // Text of change.
        var text = data.replace(pattern_amp, '&amp;').replace(pattern_lt, '&lt;')
            .replace(pattern_gt, '&gt;').replace(pattern_para, '&para;<br>');
        switch (op) {
          case DIFF_INSERT:
            html[x] = '';
            break;
          case DIFF_DELETE:
            html[x] = '<span style="background:#FF0033;">' + text + '</span>';
            break;
          case DIFF_EQUAL:
            html[x] = '<span>' + text + '</span>';
            break;
        }
      }
      return html.join('');
    };
  }


また、ライセンスがApache License, Version 2.0のためサイト内、githubApache License, Version 2.0とライブラリーを使用している旨を表記しました。

textareaの裏に文章を表示させてその文章をtextarea内で操作している風にする

textareaと同じ階層のdivタグのさらに子要素をposition: absolute、z-index: -1にして力技でtextareaと重ね合わせて(textareaの裏にぴったりdivタグがある状態)、

以下のようにtextareaを透けさして裏を表示しました。

    //textareaの背景と文字を透明化
    $(".lined").css('background-color', 'transparent');
    $(".lined").css('color', 'transparent');
    $(".lined").css('caret-color', 'black');


textarea内の折返しについてはtextareaのwrap="hard"と裏のword-break: break-wordがシンクロしてくれました。

問題点

textareaとその裏のスクロールを連動させているのですが、改行だけだと裏のdivタグには一行追加されずスクロールがずれてしまうという問題点があります。。。

  //textareaとスクロール対応
  textareaRight.scroll(function() {
    var textareaScrollTopRight = textareaRight.scrollTop();
    backScrollRight.scrollTop(textareaScrollTopRight);
  });

  textareaLeft.scroll(function() {
    var textareaScrollTopLeft = textareaLeft.scrollTop();
    backScrollLeft.scrollTop(textareaScrollTopLeft);
  });

  //textareaにイベントが発生したなら
  textareaLeft.on('input', textMatch);
  textareaRight.on('input', textMatch);

function textMatch() {
    //イベント時もスクロール反応
    var textareaScrollTopRight = textareaRight.scrollTop();
    backScrollRight.scrollTop(textareaScrollTopRight);

    var textareaScrollTopLeft = textareaLeft.scrollTop();
    backScrollLeft.scrollTop(textareaScrollTopLeft);
  }

READMEを編集

f:id:KaneyHonest:20210314175537p:plain

GitHub Pagesでwebサイトを公開

f:id:KaneyHonest:20210314175647p:plain
SettingsからGitHub PagesのSourceを指定するだけ※表示するファイル名をindex.htmlにする


感想

最初はライブラリーというものがよくわかっていなかったのですが、2つも使えばなんとなく理解できました。

当初は文章比較部分のコードを100行以上javascriptで書いていたことによってjavascriptがちょっぴり理解できました。

教材でもライブラリーでもなく自分で書くことを通じてでしかプログラミングはうまくならないとひしひしと感じます。

GitHub

github.com

追記:コピーボタンを追加

差分を表示させたあとにそれを修正したものをコピーするボタンがあったら楽だと思い実装

f:id:KaneyHonest:20210316153631p:plain

主要参考文献

developer.mozilla.org

highfivecreate.com

github.com

amg-solution.jp

gihyo.jp

github.com

www.npmjs.com

tomo-omura.com

www.phenomena.co.jp

vividcode.hatenablog.com

okadak1990.hatenablog.com

dk521123.hatenablog.com

deeeet.com

310nae.com