Double Range

string difference search base

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/21913/139533/Double%20Range.js

  1. function SingleRange(s, f) {
  2. this.l = 0; // left boundary
  3. this.r = s.length; // right boudary
  4. this.s = s; // text content
  5. }
  6. SingleRange.prototype = r1proto = {
  7. get text() {
  8. return this.s.substring(this.l, this.r);
  9. }
  10. };
  11. function DoubleRange(s1, s2, l1, l2, e1, e2, t) {
  12. this.type = t; // node type
  13. this.r1 = this.o = new SingleRange(s1);
  14. this.o.l = l1;
  15. this.o.r = e1;
  16. this.r2 = this.p = new SingleRange(s2);
  17. this.p.l = l2;
  18. this.p.r = e2;
  19. this.debug = true; //false;
  20. this.next = this.prev = null;
  21. }
  22. cdr = function createDoubleRange(a1, a2, a3, a4, a5, a6, a7) {
  23. var l = arguments.length;
  24. return new DoubleRange(a1, a2, l == 3 ? 0 : a3, l == 3 ? 0 : a4, l == 3 ? a1.length : l == 5 ? a3 : a5, l == 3 ? a2.length : l == 5 ? a4 : a6, l == 3 ? a3 : l == 5 ? a5 : a7);
  25. };
  26. DoubleRange.prototype = {
  27. toString: function () {
  28. return this.type + ' [' + this.o.l + '-' + this.o.r + ']&[' + this.p.l + '-' + this.p.r + ']:<' + this.o.text + (this.same ? '' : '>&<' + this.p.text) + '>';
  29. },
  30. get length() {
  31. return (this.o.r - this.o.l + this.p.r - this.p.l) / 2;
  32. },
  33. get lMin() {
  34. return Math.min(this.o.r - this.o.l, this.p.r - this.p.l);
  35. },
  36. get lMax() {
  37. return Math.max(this.o.r - this.o.l, this.p.r - this.p.l);
  38. },
  39. collapse: function collapse(toEnd) {
  40. this.o.r = this.o.l = toEnd ? this.o.r : this.o.l;
  41. this.p.r = this.p.l = toEnd ? this.p.r : this.p.l;
  42. return this;
  43. },
  44. get empty() {
  45. return this.o.l == this.o.r && this.p.l == this.p.s;
  46. },
  47. get collapsed() {
  48. return this.o.l == this.o.r || this.p.l == this.p.s;
  49. },
  50. get same() {
  51. return this.o.text == this.p.text;
  52. },
  53. get clone() {
  54. return new DoubleRange(this.o.s, this.p.s, this.o.l, this.p.l, this.o.r, this.p.r, this.type);
  55. },
  56. get canMoveRight() {
  57. return (!this.next || this.next.o.l > this.o.r && this.next.p.l > this.p.r) && this.o.r < this.o.s.length && this.p.r < this.p.s.length && this.o.s.charAt(this.o.r) == this.p.s.charAt(this.p.r);
  58. },
  59. get moveRight() {
  60. this.o.r++;
  61. this.p.r++;
  62. return this;
  63. },
  64. get canMoveLeft() {
  65. return (!this.prev || this.prev.o.r < this.o.l && this.prev.p.r < this.p.l) && this.o.l > 0 && this.p.l > 0 && this.o.s.charAt(this.o.l - 1) == this.p.s.charAt(this.p.l - 1);
  66. },
  67. get moveLeft() {
  68. this.o.l--;
  69. this.p.l--;
  70. return this;
  71. },
  72. expland: function () {
  73. while (this.canMoveRight) this.moveRight;
  74. while (this.canMoveLeft) this.moveLeft;
  75. return this;
  76. },
  77. get canShrinkLeft() {
  78. return !this.collapsed && this.o.s.charAt(this.o.l) == this.p.s.charAt(this.p.l);
  79. },
  80. get shrinkLeft() {
  81. this.o.l++;
  82. this.p.l++;
  83. return this;
  84. },
  85. get canShrinkRight() {
  86. return !this.collapsed && this.o.s.charAt(this.o.r - 1) == this.p.s.charAt(this.p.r - 1);
  87. },
  88. get shrinkRight() {
  89. this.o.r--;
  90. this.p.r--;
  91. return this;
  92. },
  93. canSplit: function (d) {
  94. var s = this.o.s.substr(this.o.l + d, 3),
  95. i,
  96. j;
  97. return this.lMin > 3 && this.lMax > d + 3 && (i = this.o.text.indexOf(s)) != - 1 && i == this.o.text.lastIndexOf(s) && (j = this.p.text.indexOf(s)) != - 1 && j == this.p.text.lastIndexOf(s);
  98. },
  99. split: function (d) {
  100. var c = this.next = this.clone;
  101. c.prev = this;
  102. this.next = c;
  103. var s = this.o.s.substr(this.o.l + d, 3),
  104. i = this.o.text.indexOf(s),
  105. j = this.p.text.indexOf(s);
  106. this.o.r = c.o.l += i + 1;
  107. this.p.r = c.p.l += j + 1;
  108. return c;
  109. },
  110. trySplit:function(d){
  111. if(!this.canSplit(d))return;
  112. var c = this.split(d+1);
  113. while (this.canShrinkRight) this.shrinkRight;
  114. while (c.canShrinkLeft) c.shrinkLeft;
  115. return c;
  116. }
  117. };
  118. function diff(s1, s2) {
  119. var r = cdr(s1, s2, 'diff');
  120. while (r.canShrinkLeft) r.shrinkLeft;
  121. var c = r,
  122. d;
  123. while (c) {
  124. for (var i = 0; i < 10; i++) {
  125. d = c.trySplit(i);
  126. if (d) break;
  127. }
  128. if (d) c = d;else break;
  129. }
  130. while (r.canShrinkRight) r.shrinkRight;
  131. return c;
  132. }
  133.  
  134. function highlightTypo(text, edit) {
  135. console.log(text + '\n' + edit);
  136. var r = rangy.fastFind(text);
  137. var i = 0;
  138. var u = diff(text, edit);
  139.  
  140. var n = r.extractContents().childNodes;
  141. var e = $('<span/>').append(n).addClass('typo-cont').attr('contenteditable', true);
  142. r.insertNode(e[0]);
  143.  
  144. function highlightTypoEdit(typo) {
  145. if (typo.empty) return;
  146. var r = rangy.createRange();
  147. r.selectNodeContents(e[0]);
  148. r.collapse(1);
  149. r.moveStart(typo.o.l);
  150. r.moveEnd(typo.o.r - typo.o.l);
  151. var n = r.extractContents().childNodes;
  152. var p = $('<span/>').append(n);
  153. p.addClass('typo').attr('typo', typo.p.text);
  154. r.insertNode(p[0]);
  155. }
  156.  
  157. while (u) {
  158. //noprotect
  159. highlightTypoEdit(u);
  160. u = u.prev;
  161. }
  162. return e; //rangy.toRange(e);
  163. }
  164.  
  165. function styleTypo(e) {
  166. var id = 'typo' + Math.round(Math.random() * 99999);
  167. e.attr('id', id);
  168. var b = e.find('.typo');
  169. var s = $('<style/>').appendTo($('head'))[0];
  170. s.innerHTML = id + ':hover .typo::before,.typo:hover::before,' + id + ':active .typo::before,.typo:active::before,' + id + ':focus .typo::before,.typo:focus::before,.t::before{ top:' + (-e.height() + b.height()) + 'px; border-top-width:' + (e.height() - b.height()) + 'px;}' + id + ':hover .typo::after,.typo:hover::after,' + id + ':active .typo::after,.typo:active::after,' + id + ':focus .typo::after,.typo:focus::after { top:' + (-e.height() - b.height() + 4) + 'px; }';
  171. return e;
  172. }