Greasy Fork

Greasy Fork is available in English.

Bangumi-History-Diff

compare two versions of subject history

当前为 2015-08-20 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Bangumi-History-Diff
// @namespace   BHD
// @include     /https?:\/\/(bgm|bangumi|chii)\.(tv|in)\/subject/\d+\/edit/
// @include     /https?:\/\/(bgm|bangumi|chii)\.(tv|in)\/subject/\d+\/edit_detail/diff\/\d+\.\.\.\d+/
// @version     0.0.2
// @grant       none
// @require     https://code.jquery.com/jquery-2.1.1.min.js
// @description compare two versions of subject history
// ==/UserScript==

var domain, func, uri, params = {};
var version1, version2;

//----------------------------------------
//---- Edit ------------------------------
//----------------------------------------
editController = function() {
  $('<div id="diff-launcher"><input type="number" name="diff-left" class="inputtext" placeholder="左对比(通常是老版本)"><input type="number" name="diff-right" class="inputtext" placeholder="右对比(通常是新版本)"><input type="button" class="inputBtn" value="对比" name="diff-launch"></div>').insertBefore($('#pagehistory'));

  $('#pagehistory li a').each(function() {
    var hrefMatch = $(this).attr('href').match(/undo\/(\d+)/);
    if(hrefMatch == null) return;
    var version = hrefMatch[1];
  
    $('<span>| <a href="#" class="l diff-add2left" data-version="' + version + '">加到左边对比</a> | <a href="#" class="l diff-add2right" data-version="' + version + '">加到右边对比</a></span>').insertAfter(this);
  });
  
  //binding events
  $('input[name="diff-launch"]').click(function() {
    window.location.href = '/subject/' + params.subject + '/edit_detail/diff/' + $('input[name="diff-left"]').val() + '...' + $('input[name="diff-right"').val();
  });
  
  $('.diff-add2left').click(function() {
    $('input[name="diff-left"]').val($(this).attr('data-version'));
  });

  $('.diff-add2right').click(function() {
    $('input[name="diff-right"]').val($(this).attr('data-version'));
  });
}

//----------------------------------------
//---- Diff ------------------------------
//----------------------------------------

diffController = function() {
//Request the first version and load insert it into document.
$.get('/subject/' + params.subject + '/edit_detail/undo/' + params.ver1, function(data) {
  $('body').html(data);
  
  //Change the links in navigation bar.
  $('.navSubTabs .focus').removeClass('focus');
  $('.navSubTabs').append('<li><a class="focus" href="#">对比</a></li>');
  
  //Get all infomations we need.
  var info = {ver1: {}, ver2: {}};
  //条目标题
  info.ver1.title = $('input[name="subject_title"]').val();
  //Infobox
  info.ver1.infobox = $('#subject_infobox').val();
  //简介
  info.ver1.summary = $('#subject_summary').val();
  
  //Clean workspace
  $('#columnInSubjectA').html('<h2>/ 正在对比版本 <a href="/subject/' + params.subject + '/edit_detail/undo/' + params.ver1 + '">' + params.ver1 + '</a> 与 <a href="/subject/' + params.subject + '/edit_detail/undo/' + params.ver2 + '">' + params.ver2 + '</a>' +
                              '    <a class="chiiBtn" href="/subject/' + params.subject + '/edit_detail/diff/' + params.ver2 + '...' + params.ver1 + '"><span>交换方向</span></a></small></h2>' +
                              '<div id="diff-workspace">' +
                              '<style>#diff-workspace h1 { margin: 6px; padding: 3px; font-size: 18px; border-bottom: 1px solid #777; } .diff-added { background: #e9efe9; } .diff-deleted { background: #feebeb; } .diff-modified { background: #faffd9; } </style>' +
                              '<h1>标题</h1> <table id="diff-title" class="settings" width="100%" cellpadding="5"><thead><tr><td>版本 #' + params.ver1 + '</td><td>版本 #' + params.ver2 + '</td></tr></thead><tbody></tbody></table>' + 
                              '<h1>Infobox</h1> <table id="diff-infobox" class="settings" width="100%" cellpadding="5"><thead><tr><td></td><td>版本 #' + params.ver1 + '</td><td>版本 #' + params.ver2 + '</td></tr></thead><tbody></tbody></table>' + 
                              '<h1>简介</h1> <table id="diff-summary" class="settings" width="100%" cellpadding="5"><thead><tr><td>版本 #' + params.ver1 + '</td><td>版本 #' + params.ver2 + '</td></tr></thead><tbody></tbody></table>' +
                              '</div>');

  //Loading another version and then diff them.
  $.get('/subject/' + params.subject + '/edit_detail/undo/' + params.ver2, function(data) {
    //Remove the input box, and add the table element for diff view.
    //[\S\s]* => See https://stackoverflow.com/questions/26929891/regex-to-match-a-multi-line-string
    info.ver2.title = data.match(/subject_title" class="inputtext" type="text" value="(.+?)" \/>/)[1];
    info.ver2.infobox = data.match(/subject_infobox"[^>]+>([\S\s]*?)<\/textarea>/m)[1];
    info.ver2.summary = data.match(/subject_summary"[^>]+>([\S\s]*?)<\/textarea>/m)[1];

    //Diff - Title
    $('#diff-title tbody').append('<tr><td>' + info.ver1.title + '</td><td>' + info.ver2.title + '</td></tr>');

    //Diff - Infobox
    var infobox = {ver1: {}, ver2: {}};
    infobox.ver1 = info.ver1.infobox.split(/\n/);
    infobox.ver2 = info.ver2.infobox.split(/\n/);

    infoboxCompare = compare(infobox.ver1, infobox.ver2);

    for(i in infoboxCompare) {
      switch(infoboxCompare[i].act) {
        case 'match':
          $('#diff-infobox tbody').append('<tr class="diff-match"><th></th><td>' + infoboxCompare[i].left + '</td><td>' + infoboxCompare[i].right + '</td></tr>');
          break;
        case 'added':
          $('#diff-infobox tbody').append('<tr class="diff-added"><th>++</th><td></td><td>' + infoboxCompare[i].right + '</td></tr>');
          break;
        case 'deleted':
          $('#diff-infobox tbody').append('<tr class="diff-deleted"><th>--</th><td>' + infoboxCompare[i].left + '</td><td></td></tr>');
          break;
        case 'modified':
          $('#diff-infobox tbody').append('<tr class="diff-modified"><th>MM</th><td>' + infoboxCompare[i].left + '</td><td>' + infoboxCompare[i].right + '</td></tr>');
          break;
      }
    }
    
    //Diff - Summary
    $('#diff-summary tbody').append('<tr><td>' + info.ver1.summary + '</td><td>' + info.ver2.summary + '</td></tr>');

  }); //$.get('/subj...ver2...
}); //$.get('/subj...ver1...
}
  
//----------------------------------------
//---- Functions -------------------------
//----------------------------------------
compare = function(left, right) {
  var leftPointer = 0, rightPointer = 0;
  var retval = [];

  while(leftPointer < left.length) {
    //May be they are the same...
    if(left[leftPointer] == right[rightPointer]) {
      retval.push({act: 'match', left: left[leftPointer], right: right[rightPointer]});
      leftPointer++;
      rightPointer++;
      continue;
    }

    var matchShift = 0;
    var leftShift = 0, rightShift = 0;
    var leftTitleMatch = false, rightTitleMatch = false;
      
    while((rightPointer + rightShift) < right.length) {
      //for the line start with "|", we just compare their title("|title=", "|title =")
      if((left[leftPointer].length > 0 && left[leftPointer][0] == '|') &&
         (right[rightPointer + rightShift].length > 0 && right[rightPointer + rightShift][0] == '|')) {
        var leftTitle = left[leftPointer].match(/\|(.+?)=/)[1];
        var rightTitle = right[rightPointer + rightShift].match(/\|(.+?)=/)[1];
        if(leftTitle == rightTitle) {
          rightTitleMatch = true;
          break;
        }
      } else if(left[leftPointer] == right[rightPointer + rightShift]) break;
      rightShift++;
    } //while rightShift...
    matchShift = rightShift;

    var leftShift = 0, rightShift = 0;
    while((leftShift + leftPointer) <= left.length - 1) {
      //for the line start with "|", we just compare their title("|title=", "|title =")
      if((left[leftPointer + leftShift].length > 0 && left[leftPointer + leftShift][0] == '|') &&
         (right[rightPointer].length > 0 && right[rightPointer][0] == '|')) {
        var leftTitle = left[leftPointer + leftShift].match(/\|(.+?)=/)[1];
        var rightTitle = right[rightPointer].match(/\|(.+?)=/)[1];
        if(leftTitle == rightTitle) {
          leftTitleMatch = true;
          break;
        }
      } else if(left[leftPointer + leftShift] == right[rightPointer]) break;
      leftShift++;
    } //while leftShift...
    rightShift = matchShift;

    //Comparing...
      
    //Modified
    if(((leftPointer + leftShift) >= left.length - 1) && ((rightPointer + rightShift) >= right.length - 1)) {
      retval.push({act: 'deleted', left: left[leftPointer]});
      retval.push({act: 'added', right: right[rightPointer]});
      leftPointer++;
      rightPointer++;
      continue;
    }
      
    //Delete
    if(leftShift < rightShift) {
      for(var i = 0; i < leftShift; i++) {
        retval.push({act: 'deleted', left: left[leftPointer + i]});
      }
      var leftContent = left[leftPointer + leftShift].match(/=(.+)/);
      var rightContent = right[rightPointer].match(/=(.+)/);
      retval.push({act: (leftContent == rightContent ? 'match' : 'modified'), left: left[leftPointer + leftShift], right: right[rightPointer]});
      leftPointer += leftShift + 1;
      rightPointer++;
      continue;
    }

    //Add
    if(leftShift > rightShift) {
      for(var i = 0; i < rightShift; i++) {
        retval.push({act: 'added', right: right[rightPointer + i]});
      }
      var leftContent = left[leftPointer].match(/=(.+)/);
      var rightContent = right[rightPointer + rightShift].match(/=(.+)/);
      retval.push({act: (leftContent == rightContent ? 'match' : 'modified'), left: left[leftPointer], right: right[rightPointer + rightShift]});
      leftPointer++;
      rightPointer += rightShift + 1;
      continue;
    }
    
    //Else... => the title of two lines are the same
    var leftContent = left[leftPointer].match(/=(.+)/);
    var rightContent = right[rightPointer].match(/=(.+)/);
    retval.push({act: (leftContent == rightContent ? 'match' : 'modified'), left: left[leftPointer], right: right[rightPointer]});
    leftPointer++;
    rightPointer++;
    continue;
  } //while leftPointer...
  return retval;
}


//----------------------------------------
//---- Routing & Bootstrap ---------------
//----------------------------------------

$(function() {
  var urlMatch = window.location.href.match(/\/\/(bgm|bangumi|chii).(tv|in)(\/.+)/);
  uri = urlMatch[3];

  //Domain
  switch(urlMatch[1]) {
    case 'bgm':
      domain = 'bgm.tv';
      break;
    case 'bangumi':
      domain = 'bangumi.tv';
      break;
    case 'chii':
      domain = 'chii.in';
      break;
  }
  
  //URI & Params
  switch(true) {
    case (urlMatch[3].search('diff') >= 0):
      func = 'diff';

      var matchParams = urlMatch[3].match(/\/subject\/(\d+)\/edit_detail\/diff\/(\d+)...(\d+)/);
      params = {
        subject: matchParams[1],
        ver1: matchParams[2],
        ver2: matchParams[3]
      };
      diffController();
      break;
    case (urlMatch[3].search('edit') >= 0):
      func = 'edit';

      var matchParams = urlMatch[3].match(/\/subject\/(\d+)\/edit/);
      params = {
        subject: matchParams[1]
      };
      editController();
      break;
  }
});