Skip to content

Commit b661db6

Browse files
author
Bill Long
committed
Use a javascript object as a hashtable to map the tags
In this approach we use a hashtable for mapping instead of iterating through a for loop. This approach should be faster in a situation where you're diffing HTML that has a whole bunch of tags.
1 parent 2d50b19 commit b661db6

2 files changed

Lines changed: 24 additions & 74 deletions

File tree

angular-rich-text-diff.js

Lines changed: 17 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
/// <reference path="bower_components/dt-angular/angular.d.ts"/>
1+
/// <reference path="bower_components/dt-angular/angular.d.ts"/>
22
/// <reference path="google-diff-match-patch.d.ts"/>
33
var AngularRichTextDiff;
44
(function (AngularRichTextDiff) {
55
'use strict';
6-
76
var RichTextDiffController = (function () {
87
function RichTextDiffController($scope, $sce) {
98
var _this = this;
@@ -16,7 +15,7 @@ var AngularRichTextDiff;
1615
$scope.$watch('right', function () {
1716
_this.doDiff();
1817
});
19-
this.tagMap = [];
18+
this.tagMap = {};
2019
this.dmp = new diff_match_patch();
2120
this.doDiff();
2221
}
@@ -30,23 +29,22 @@ var AngularRichTextDiff;
3029
diffs[x][1] = this.insertTagsForOperation(diffs[x][1], diffs[x][0]);
3130
diffOutput += this.convertDiffableBackToHtml(diffs[x][1]);
3231
}
33-
3432
this.$scope.diffOutput = this.$sce.trustAsHtml(diffOutput);
3533
};
36-
3734
RichTextDiffController.prototype.insertTagsForOperation = function (diffableString, operation) {
3835
var openTag = '';
3936
var closeTag = '';
4037
if (operation === 1) {
4138
openTag = '<ins>';
4239
closeTag = '</ins>';
43-
} else if (operation === -1) {
40+
}
41+
else if (operation === -1) {
4442
openTag = '<del>';
4543
closeTag = '</del>';
46-
} else {
44+
}
45+
else {
4746
return diffableString;
4847
}
49-
5048
var outputString = openTag;
5149
var isOpen = true;
5250
for (var x = 0; x < diffableString.length; x++) {
@@ -56,35 +54,31 @@ var AngularRichTextDiff;
5654
outputString += openTag;
5755
isOpen = true;
5856
}
59-
6057
outputString += diffableString[x];
61-
} else {
58+
}
59+
else {
6260
// We just hit one of our mapped unicode characters. Close our tag.
6361
if (isOpen) {
6462
outputString += closeTag;
6563
isOpen = false;
6664
}
67-
6865
outputString += diffableString[x];
6966
}
7067
}
71-
7268
if (isOpen)
7369
outputString += closeTag;
74-
7570
return outputString;
7671
};
77-
7872
RichTextDiffController.prototype.convertHtmlToDiffableString = function (htmlString) {
7973
var diffableString = '';
80-
8174
var offset = 0;
8275
while (offset < htmlString.length) {
8376
var tagStart = htmlString.indexOf('<', offset);
8477
if (tagStart < 0) {
8578
diffableString += htmlString.substr(offset);
8679
break;
87-
} else {
80+
}
81+
else {
8882
var tagEnd = htmlString.indexOf('>', tagStart);
8983
if (tagEnd < 0) {
9084
// Invalid HTML
@@ -93,71 +87,46 @@ var AngularRichTextDiff;
9387
diffableString += htmlString.substr(offset, tagStart - offset);
9488
break;
9589
}
96-
9790
var tagString = htmlString.substr(tagStart, tagEnd + 1 - tagStart);
98-
9991
// Is this tag already mapped?
100-
var unicodeCharacter = '';
101-
for (var x = 0; x < this.tagMap.length; x++) {
102-
if (this.tagMap[x].tag === tagString) {
103-
unicodeCharacter = this.tagMap[x].unicodeReplacement;
104-
break;
105-
}
106-
}
107-
108-
if (unicodeCharacter === '') {
92+
var unicodeCharacter = this.tagMap[tagString];
93+
if (unicodeCharacter === undefined) {
10994
// Nope, need to map it
11095
unicodeCharacter = String.fromCharCode(this.unicodeRangeStart + this.tagMap.length);
111-
this.tagMap.push({
112-
tag: tagString,
113-
unicodeReplacement: unicodeCharacter
114-
});
96+
this.tagMap[tagString] = unicodeCharacter;
97+
this.tagMap[unicodeCharacter] = tagString;
11598
}
116-
11799
// At this point it has been mapped, so now we can use it
118100
diffableString += htmlString.substr(offset, tagStart - offset);
119101
diffableString += unicodeCharacter;
120-
121102
offset = tagEnd + 1;
122103
}
123104
}
124-
125105
return diffableString;
126106
};
127-
128107
RichTextDiffController.prototype.convertDiffableBackToHtml = function (diffableString) {
129108
var htmlString = '';
130-
131109
for (var x = 0; x < diffableString.length; x++) {
132110
var charCode = diffableString.charCodeAt(x);
133111
if (charCode < this.unicodeRangeStart) {
134112
htmlString += diffableString[x];
135113
continue;
136114
}
137-
138-
var tagString = '';
139-
for (var y = 0; y < this.tagMap.length; y++) {
140-
if (this.tagMap[y].unicodeReplacement === diffableString[x]) {
141-
tagString = this.tagMap[y].tag;
142-
break;
143-
}
144-
}
145-
115+
var tagString = this.tagMap[diffableString[x]];
146116
if (tagString === '') {
147117
// We somehow have a character that is above our range but didn't map
148118
// Do we need to add an upper bound or change the range?
149119
htmlString += diffableString[x];
150-
} else {
120+
}
121+
else {
151122
htmlString += tagString;
152123
}
153124
}
154-
155125
return htmlString;
156126
};
157127
RichTextDiffController.$inject = ['$scope', '$sce'];
158128
return RichTextDiffController;
159129
})();
160-
161130
function richTextDiff() {
162131
var directive = {
163132
restrict: 'E',
@@ -168,11 +137,8 @@ var AngularRichTextDiff;
168137
template: '<div ng-bind-html="diffOutput"></div>',
169138
controller: RichTextDiffController
170139
};
171-
172140
return directive;
173141
}
174-
175142
angular.module('angular-rich-text-diff', ['ngSanitize']);
176-
177143
angular.module('angular-rich-text-diff').directive('richTextDiff', richTextDiff);
178144
})(AngularRichTextDiff || (AngularRichTextDiff = {}));

angular-rich-text-diff.ts

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ module AngularRichTextDiff {
2020
static $inject = ['$scope', '$sce'];
2121

2222
unicodeRangeStart = 0xE000;
23-
tagMap: Array<ITagMapping>;
23+
tagMap: any;
2424
dmp: diff_match_patch;
2525

2626
constructor(public $scope: IRichTextDiffScope, public $sce: ng.ISCEService) {
2727
$scope.$watch('left', () => { this.doDiff(); });
2828
$scope.$watch('right', () => { this.doDiff(); });
29-
this.tagMap = [];
29+
this.tagMap = {};
3030
this.dmp = new diff_match_patch();
3131
this.doDiff();
3232
}
@@ -107,21 +107,12 @@ module AngularRichTextDiff {
107107
var tagString = htmlString.substr(tagStart, tagEnd + 1 - tagStart);
108108

109109
// Is this tag already mapped?
110-
var unicodeCharacter = '';
111-
for (var x = 0; x < this.tagMap.length; x++) {
112-
if (this.tagMap[x].tag === tagString) {
113-
unicodeCharacter = this.tagMap[x].unicodeReplacement;
114-
break;
115-
}
116-
}
117-
118-
if (unicodeCharacter === '') {
110+
var unicodeCharacter = this.tagMap[tagString];
111+
if (unicodeCharacter === undefined) {
119112
// Nope, need to map it
120113
unicodeCharacter = String.fromCharCode(this.unicodeRangeStart + this.tagMap.length);
121-
this.tagMap.push({
122-
tag: tagString,
123-
unicodeReplacement: unicodeCharacter
124-
});
114+
this.tagMap[tagString] = unicodeCharacter;
115+
this.tagMap[unicodeCharacter] = tagString;
125116
}
126117

127118
// At this point it has been mapped, so now we can use it
@@ -145,14 +136,7 @@ module AngularRichTextDiff {
145136
continue;
146137
}
147138

148-
var tagString = '';
149-
for (var y = 0; y < this.tagMap.length; y++) {
150-
if (this.tagMap[y].unicodeReplacement === diffableString[x]) {
151-
tagString = this.tagMap[y].tag;
152-
break;
153-
}
154-
}
155-
139+
var tagString = this.tagMap[diffableString[x]];
156140
if (tagString === '') {
157141
// We somehow have a character that is above our range but didn't map
158142
// Do we need to add an upper bound or change the range?

0 commit comments

Comments
 (0)