Lift gr-syntax-layer into gr-diff-host

This change decouples gr-diff-builder and gr-syntax-layer. gr-syntax-
layer will now live in gr-diff-host.
As a result, from the perspective of gr-diff/gr-diff-builder, plugin
layers and the syntax layer will now be part of the same list.

(This change fixes a time reporting regression in https://gerrit-review.googlesource.com/c/gerrit/+/239972.)

A future potential refactor could also lift gr-coverage-layer instances
in a similar fashion.

Change-Id: I47e91fdac00e17460aab9ca57e4569ade63c2eeb
This commit is contained in:
Mayank Kumar
2019-10-03 18:04:08 -07:00
parent 897a9c218a
commit 41b0f951fc
9 changed files with 245 additions and 147 deletions

View File

@@ -20,7 +20,6 @@ limitations under the License.
<link rel="import" href="../gr-coverage-layer/gr-coverage-layer.html"> <link rel="import" href="../gr-coverage-layer/gr-coverage-layer.html">
<link rel="import" href="../gr-diff-processor/gr-diff-processor.html"> <link rel="import" href="../gr-diff-processor/gr-diff-processor.html">
<link rel="import" href="../gr-ranged-comment-layer/gr-ranged-comment-layer.html"> <link rel="import" href="../gr-ranged-comment-layer/gr-ranged-comment-layer.html">
<link rel="import" href="../gr-syntax-layer/gr-syntax-layer.html">
<dom-module id="gr-diff-builder"> <dom-module id="gr-diff-builder">
<template> <template>
@@ -30,9 +29,6 @@ limitations under the License.
<gr-ranged-comment-layer <gr-ranged-comment-layer
id="rangeLayer" id="rangeLayer"
comment-ranges="[[commentRanges]]"></gr-ranged-comment-layer> comment-ranges="[[commentRanges]]"></gr-ranged-comment-layer>
<gr-syntax-layer
id="syntaxLayer"
diff="[[diff]]"></gr-syntax-layer>
<gr-coverage-layer <gr-coverage-layer
id="coverageLayerLeft" id="coverageLayerLeft"
coverage-ranges="[[_leftCoverageRanges]]" coverage-ranges="[[_leftCoverageRanges]]"
@@ -64,13 +60,6 @@ limitations under the License.
UNIFIED: 'UNIFIED_DIFF', UNIFIED: 'UNIFIED_DIFF',
}; };
// If any line of the diff is more than the character limit, then disable
// syntax highlighting for the entire file.
const SYNTAX_MAX_LINE_LENGTH = 500;
// Disable syntax highlighting if the overall diff is too large.
const SYNTAX_MAX_DIFF_LENGTH = 20000;
const TRAILING_WHITESPACE_PATTERN = /\s+$/; const TRAILING_WHITESPACE_PATTERN = /\s+$/;
Polymer({ Polymer({
@@ -84,18 +73,11 @@ limitations under the License.
*/ */
/** /**
* Fired when the diff finishes rendering text content and starts * Fired when the diff finishes rendering text content.
* syntax highlighting.
* *
* @event render-content * @event render-content
*/ */
/**
* Fired when the diff finishes syntax highlighting.
*
* @event render-syntax
*/
properties: { properties: {
diff: Object, diff: Object,
diffPath: String, diffPath: String,
@@ -138,7 +120,7 @@ limitations under the License.
* @type {?Object} * @type {?Object}
*/ */
_cancelableRenderPromise: Object, _cancelableRenderPromise: Object,
pluginLayers: { layers: {
type: Array, type: Array,
value: [], value: [],
}, },
@@ -171,11 +153,10 @@ limitations under the License.
// attached before plugins are installed. // attached before plugins are installed.
this._setupAnnotationLayers(); this._setupAnnotationLayers();
this.$.syntaxLayer.enabled = prefs.syntax_highlighting;
this._showTabs = !!prefs.show_tabs; this._showTabs = !!prefs.show_tabs;
this._showTrailingWhitespace = !!prefs.show_whitespace_errors; this._showTrailingWhitespace = !!prefs.show_whitespace_errors;
// Stop the processor and syntax layer (if they're running). // Stop the processor if it's running.
this.cancel(); this.cancel();
this._builder = this._getDiffBuilder(this.diff, prefs); this._builder = this._getDiffBuilder(this.diff, prefs);
@@ -198,16 +179,6 @@ limitations under the License.
} }
this.dispatchEvent(new CustomEvent('render-content', this.dispatchEvent(new CustomEvent('render-content',
{bubbles: true, composed: true})); {bubbles: true, composed: true}));
if (this._diffTooLargeForSyntax()) {
this.$.syntaxLayer.enabled = false;
}
return this.$.syntaxLayer.process();
})
.then(() => {
this.dispatchEvent(new CustomEvent(
'render-syntax', {bubbles: true, composed: true}));
})); }));
return this._cancelableRenderPromise return this._cancelableRenderPromise
.finally(() => { this._cancelableRenderPromise = null; }) .finally(() => { this._cancelableRenderPromise = null; })
@@ -220,7 +191,6 @@ limitations under the License.
_setupAnnotationLayers() { _setupAnnotationLayers() {
const layers = [ const layers = [
this._createTrailingWhitespaceLayer(), this._createTrailingWhitespaceLayer(),
this.$.syntaxLayer,
this._createIntralineLayer(), this._createIntralineLayer(),
this._createTabIndicatorLayer(), this._createTabIndicatorLayer(),
this.$.rangeLayer, this.$.rangeLayer,
@@ -228,8 +198,8 @@ limitations under the License.
this.$.coverageLayerRight, this.$.coverageLayerRight,
]; ];
if (this.pluginLayers) { if (this.layers) {
layers.push(...this.pluginLayers); layers.push(...this.layers);
} }
this._layers = layers; this._layers = layers;
}, },
@@ -307,7 +277,6 @@ limitations under the License.
cancel() { cancel() {
this.$.processor.cancel(); this.$.processor.cancel();
this.$.syntaxLayer.cancel();
if (this._cancelableRenderPromise) { if (this._cancelableRenderPromise) {
this._cancelableRenderPromise.cancel(); this._cancelableRenderPromise.cancel();
this._cancelableRenderPromise = null; this._cancelableRenderPromise = null;
@@ -446,44 +415,10 @@ limitations under the License.
}; };
}, },
/**
* @return {boolean} whether any of the lines in _groups are longer
* than SYNTAX_MAX_LINE_LENGTH.
*/
_anyLineTooLong() {
return this._groups.reduce((acc, group) => {
return acc || group.lines.reduce((acc, line) => {
return acc || line.text.length >= SYNTAX_MAX_LINE_LENGTH;
}, false);
}, false);
},
_diffTooLargeForSyntax() {
return this._anyLineTooLong() ||
this.getDiffLength() > SYNTAX_MAX_DIFF_LENGTH;
},
setBlame(blame) { setBlame(blame) {
if (!this._builder || !blame) { return; } if (!this._builder || !blame) { return; }
this._builder.setBlame(blame); this._builder.setBlame(blame);
}, },
/**
* Get the approximate length of the diff as the sum of the maximum
* length of the chunks.
* @return {number}
*/
getDiffLength() {
return this.diff.content.reduce((sum, sec) => {
if (sec.hasOwnProperty('ab')) {
return sum + sec.ab.length;
} else {
return sum + Math.max(
sec.hasOwnProperty('a') ? sec.a.length : 0,
sec.hasOwnProperty('b') ? sec.b.length : 0);
}
}, 0);
},
}); });
})(); })();
</script> </script>

View File

@@ -590,38 +590,38 @@ limitations under the License.
}); });
}); });
suite('layers from plugins', () => { suite('layers', () => {
let element; let element;
let initialLayersCount; let initialLayersCount;
let withPluginLayerCount; let withLayerCount;
setup(() => { setup(() => {
const pluginLayers = []; const layers = [];
element = fixture('basic'); element = fixture('basic');
element.pluginLayers = pluginLayers; element.layers = layers;
element._showTrailingWhitespace = true; element._showTrailingWhitespace = true;
element._setupAnnotationLayers(); element._setupAnnotationLayers();
initialLayersCount = element._layers.length; initialLayersCount = element._layers.length;
}); });
test('no plugin layers', () => { test('no layers', () => {
element._setupAnnotationLayers(); element._setupAnnotationLayers();
assert.equal(element._layers.length, initialLayersCount); assert.equal(element._layers.length, initialLayersCount);
}); });
suite('with plugin layers', () => { suite('with layers', () => {
const pluginLayers = [{}, {}]; const layers = [{}, {}];
setup(() => { setup(() => {
element = fixture('basic'); element = fixture('basic');
element.pluginLayers = pluginLayers; element.layers = layers;
element._showTrailingWhitespace = true; element._showTrailingWhitespace = true;
element._setupAnnotationLayers(); element._setupAnnotationLayers();
withPluginLayerCount = element._layers.length; withLayerCount = element._layers.length;
}); });
test('with plugin layers', () => { test('with layers', () => {
element._setupAnnotationLayers(); element._setupAnnotationLayers();
assert.equal(element._layers.length, withPluginLayerCount); assert.equal(element._layers.length, withLayerCount);
assert.equal(initialLayersCount + pluginLayers.length, assert.equal(initialLayersCount + layers.length,
withPluginLayerCount); withLayerCount);
}); });
}); });
}); });
@@ -733,7 +733,6 @@ limitations under the License.
element.viewMode = 'SIDE_BY_SIDE'; element.viewMode = 'SIDE_BY_SIDE';
processStub = sandbox.stub(element.$.processor, 'process') processStub = sandbox.stub(element.$.processor, 'process')
.returns(Promise.resolve()); .returns(Promise.resolve());
sandbox.stub(element, '_anyLineTooLong').returns(true);
keyLocations = {left: {}, right: {}}; keyLocations = {left: {}, right: {}};
prefs = { prefs = {
line_length: 10, line_length: 10,
@@ -862,37 +861,14 @@ limitations under the License.
.map(c => { return c.args[0].type; }); .map(c => { return c.args[0].type; });
assert.include(firedEventTypes, 'render-start'); assert.include(firedEventTypes, 'render-start');
assert.include(firedEventTypes, 'render-content'); assert.include(firedEventTypes, 'render-content');
assert.include(firedEventTypes, 'render-syntax');
done();
});
});
test('rendering normal-sized diff does not disable syntax', () => {
assert.isTrue(element.$.syntaxLayer.enabled);
});
test('rendering large diff disables syntax', done => {
// Before it renders, set the first diff line to 500 '*' characters.
element.diff.content[0].a = [new Array(501).join('*')];
const prefs = {
line_length: 10,
show_tabs: true,
tab_size: 4,
context: -1,
syntax_highlighting: true,
};
element.render(keyLocations, prefs).then(() => {
assert.isFalse(element.$.syntaxLayer.enabled);
done(); done();
}); });
}); });
test('cancel', () => { test('cancel', () => {
const processorCancelStub = sandbox.stub(element.$.processor, 'cancel'); const processorCancelStub = sandbox.stub(element.$.processor, 'cancel');
const syntaxCancelStub = sandbox.stub(element.$.syntaxLayer, 'cancel');
element.cancel(); element.cancel();
assert.isTrue(processorCancelStub.called); assert.isTrue(processorCancelStub.called);
assert.isTrue(syntaxCancelStub.called);
}); });
}); });
@@ -921,10 +897,6 @@ limitations under the License.
}); });
}); });
test('getDiffLength', () => {
assert.equal(element.getDiffLength(diff), 52);
});
test('getContentByLine', () => { test('getContentByLine', () => {
let actual; let actual;

View File

@@ -23,6 +23,7 @@ limitations under the License.
<link rel="import" href="../../shared/gr-comment-thread/gr-comment-thread.html"> <link rel="import" href="../../shared/gr-comment-thread/gr-comment-thread.html">
<link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html"> <link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
<link rel="import" href="../gr-diff/gr-diff.html"> <link rel="import" href="../gr-diff/gr-diff.html">
<link rel="import" href="../gr-syntax-layer/gr-syntax-layer.html">
<dom-module id="gr-diff-host"> <dom-module id="gr-diff-host">
<template> <template>
@@ -49,8 +50,13 @@ limitations under the License.
revision-image=[[_revisionImage]] revision-image=[[_revisionImage]]
coverage-ranges="[[_coverageRanges]]" coverage-ranges="[[_coverageRanges]]"
blame="[[_blame]]" blame="[[_blame]]"
plugin-layers="[[pluginLayers]]" layers="[[_layers]]"
diff="[[diff]]"></gr-diff> diff="[[diff]]">
</gr-diff>
<gr-syntax-layer
id="syntaxLayer"
enabled="[[_syntaxHighlightingEnabled]]"
diff="[[diff]]"></gr-syntax-layer>
<gr-js-api-interface id="jsAPI"></gr-js-api-interface> <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface> <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-reporting id="reporting" category="diff"></gr-reporting> <gr-reporting id="reporting" category="diff"></gr-reporting>

View File

@@ -35,6 +35,13 @@
SYNTAX: 'Diff Syntax Render', SYNTAX: 'Diff Syntax Render',
}; };
// Disable syntax highlighting if the overall diff is too large.
const SYNTAX_MAX_DIFF_LENGTH = 20000;
// If any line of the diff is more than the character limit, then disable
// syntax highlighting for the entire file.
const SYNTAX_MAX_LINE_LENGTH = 500;
const WHITESPACE_IGNORE_NONE = 'IGNORE_NONE'; const WHITESPACE_IGNORE_NONE = 'IGNORE_NONE';
/** /**
@@ -210,7 +217,13 @@
computed: '_computeParentIndex(patchRange.*)', computed: '_computeParentIndex(patchRange.*)',
}, },
pluginLayers: { _syntaxHighlightingEnabled: {
type: Boolean,
computed:
'_isSyntaxHighlightingEnabled(prefs.syntax_highlighting, _diff)',
},
_layers: {
type: Array, type: Array,
value: [], value: [],
}, },
@@ -235,7 +248,6 @@
'render-start': '_handleRenderStart', 'render-start': '_handleRenderStart',
'render-content': '_handleRenderContent', 'render-content': '_handleRenderContent',
'render-syntax': '_handleRenderSyntax',
'normalize-range': '_handleNormalizeRange', 'normalize-range': '_handleNormalizeRange',
}, },
@@ -263,13 +275,13 @@
this._errorMessage = null; this._errorMessage = null;
const whitespaceLevel = this._getIgnoreWhitespace(); const whitespaceLevel = this._getIgnoreWhitespace();
const pluginLayers = []; const layers = [this.$.syntaxLayer];
// Get layers from plugins (if any). // Get layers from plugins (if any).
for (const pluginLayer of this.$.jsAPI.getDiffLayers( for (const pluginLayer of this.$.jsAPI.getDiffLayers(
this.diffPath, this.changeNum, this.patchNum)) { this.diffPath, this.changeNum, this.patchNum)) {
pluginLayers.push(pluginLayer); layers.push(pluginLayer);
} }
this.push('pluginLayers', ...pluginLayers); this._layers = layers;
this._coverageRanges = []; this._coverageRanges = [];
const {changeNum, path, patchRange: {basePatchNum, patchNum}} = this; const {changeNum, path, patchRange: {basePatchNum, patchNum}} = this;
@@ -312,8 +324,20 @@
} }
this.filesWeblinks = this._getFilesWeblinks(diff); this.filesWeblinks = this._getFilesWeblinks(diff);
return new Promise(resolve => { return new Promise(resolve => {
const callback = () => { const callback = event => {
resolve(); const needsSyntaxHighlighting = event.detail
&& event.detail.contentRendered;
if (needsSyntaxHighlighting) {
this.$.reporting.time(TimingLabel.SYNTAX);
this.$.syntaxLayer.process().then(() => {
this.$.reporting.timeEnd(TimingLabel.SYNTAX);
this.$.reporting.timeEnd(TimingLabel.TOTAL);
resolve();
});
} else {
this.$.reporting.timeEnd(TimingLabel.TOTAL);
resolve();
}
this.removeEventListener('render', callback); this.removeEventListener('render', callback);
}; };
this.addEventListener('render', callback); this.addEventListener('render', callback);
@@ -856,6 +880,25 @@
item => item.__draftID === comment.__draftID); item => item.__draftID === comment.__draftID);
}, },
_isSyntaxHighlightingEnabled(preference, diff) {
if (!preference) return false;
return !this._anyLineTooLong(diff) &&
this.$.diff.getDiffLength(diff) <= SYNTAX_MAX_DIFF_LENGTH;
},
/**
* @return {boolean} whether any of the lines in diff are longer
* than SYNTAX_MAX_LINE_LENGTH.
*/
_anyLineTooLong(diff) {
return diff.content.some(section => {
const lines = section.ab ?
section.ab :
(section.a || []).concat(section.b || []);
return lines.some(line => line.length >= SYNTAX_MAX_LINE_LENGTH);
});
},
_handleRenderStart() { _handleRenderStart() {
this.$.reporting.time(TimingLabel.TOTAL); this.$.reporting.time(TimingLabel.TOTAL);
this.$.reporting.time(TimingLabel.CONTENT); this.$.reporting.time(TimingLabel.CONTENT);
@@ -863,12 +906,6 @@
_handleRenderContent() { _handleRenderContent() {
this.$.reporting.timeEnd(TimingLabel.CONTENT); this.$.reporting.timeEnd(TimingLabel.CONTENT);
this.$.reporting.time(TimingLabel.SYNTAX);
},
_handleRenderSyntax() {
this.$.reporting.timeEnd(TimingLabel.SYNTAX);
this.$.reporting.timeEnd(TimingLabel.TOTAL);
}, },
_handleNormalizeRange(event) { _handleNormalizeRange(event) {

View File

@@ -60,7 +60,7 @@ limitations under the License.
suite('plugin layers', () => { suite('plugin layers', () => {
const pluginLayers = [{}, {}]; const pluginLayers = [{annotate: () => {}}, {annotate: () => {}}];
setup(() => { setup(() => {
stub('gr-js-api-interface', { stub('gr-js-api-interface', {
getDiffLayers() { return pluginLayers; }, getDiffLayers() { return pluginLayers; },
@@ -302,24 +302,81 @@ limitations under the License.
done(); done();
}); });
test('ends content and starts syntax timer on render-content', done => { test('ends content timer on render-content', () => {
element.dispatchEvent( element.dispatchEvent(
new CustomEvent('render-content', {bubbles: true, composed: true})); new CustomEvent('render-content', {bubbles: true, composed: true}));
assert.isTrue(element.$.reporting.time.calledWithExactly(
'Diff Syntax Render'));
assert.isTrue(element.$.reporting.timeEnd.calledWithExactly( assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
'Diff Content Render')); 'Diff Content Render'));
done();
}); });
test('ends total and syntax timer on render-syntax', done => { test('ends total and syntax timer after syntax layer processing', done => {
element.dispatchEvent( let notifySyntaxProcessed;
new CustomEvent('render-syntax', {bubbles: true, composed: true})); sandbox.stub(element.$.syntaxLayer, 'process').returns(new Promise(
assert.isTrue(element.$.reporting.timeEnd.calledWithExactly( resolve => {
'Diff Total Render')); notifySyntaxProcessed = resolve;
assert.isTrue(element.$.reporting.timeEnd.calledWithExactly( }));
'Diff Syntax Render')); sandbox.stub(element.$.restAPI, 'getDiff').returns(
done(); Promise.resolve({content: []}));
element.patchRange = {};
element.$.restAPI.getDiffPreferences().then(prefs => {
element.prefs = prefs;
return element.reload();
});
// Multiple cascading microtasks are scheduled.
setTimeout(() => {
notifySyntaxProcessed();
// Assert after the notification task is processed.
Promise.resolve().then(() => {
assert.isTrue(element.$.reporting.timeEnd.calledThrice);
assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
'Diff Total Render'));
assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
'Diff Syntax Render'));
done();
});
});
});
test('ends total timer w/ no syntax layer processing', done => {
sandbox.stub(element.$.restAPI, 'getDiff').returns(
Promise.resolve({content: []}));
element.patchRange = {};
element.reload();
// Multiple cascading microtasks are scheduled.
setTimeout(() => {
assert.isTrue(element.$.reporting.timeEnd.calledOnce);
assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
'Diff Total Render'));
done();
});
});
test('completes reload promise after syntax layer processing', done => {
let notifySyntaxProcessed;
sandbox.stub(element.$.syntaxLayer, 'process').returns(new Promise(
resolve => {
notifySyntaxProcessed = resolve;
}));
sandbox.stub(element.$.restAPI, 'getDiff').returns(
Promise.resolve({content: []}));
element.patchRange = {};
let reloadComplete = false;
element.$.restAPI.getDiffPreferences().then(prefs => {
element.prefs = prefs;
return element.reload();
}).then(() => {
reloadComplete = true;
});
// Multiple cascading microtasks are scheduled.
setTimeout(() => {
assert.isFalse(reloadComplete);
notifySyntaxProcessed();
// Assert after the notification task is processed.
setTimeout(() => {
assert.isTrue(reloadComplete);
done();
});
});
}); });
}); });
@@ -1285,5 +1342,57 @@ limitations under the License.
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line, assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
Gerrit.DiffSide.RIGHT), [r]); Gerrit.DiffSide.RIGHT), [r]);
}); });
suite('syntax layer', () => {
setup(() => {
const prefs = {
line_length: 10,
show_tabs: true,
tab_size: 4,
context: -1,
syntax_highlighting: true,
};
element.prefs = prefs;
});
test('gr-diff-host provides syntax highlighting layer to gr-diff', () => {
element.patchRange = {};
element.reload();
assert.equal(element.$.diff.layers[0], element.$.syntaxLayer);
});
test('rendering normal-sized diff does not disable syntax', () => {
element._diff = {
content: [{
a: ['foo'],
}],
};
assert.isTrue(element.$.syntaxLayer.enabled);
});
test('rendering large diff disables syntax', () => {
// Before it renders, set the first diff line to 500 '*' characters.
element._diff = {
content: [{
a: [new Array(501).join('*')],
}],
};
assert.isFalse(element.$.syntaxLayer.enabled);
});
test('starts syntax layer processing on render event', done => {
sandbox.stub(element.$.syntaxLayer, 'process').returns(Promise.resolve());
sandbox.stub(element.$.restAPI, 'getDiff').returns(
Promise.resolve({content: []}));
element.patchRange = {};
element.reload();
setTimeout(() => {
element.dispatchEvent(
new CustomEvent('render', {bubbles: true, composed: true}));
assert.isTrue(element.$.syntaxLayer.process.called);
done();
});
});
});
}); });
</script> </script>

View File

@@ -378,7 +378,7 @@ limitations under the License.
line-wrapping="[[lineWrapping]]" line-wrapping="[[lineWrapping]]"
is-image-diff="[[isImageDiff]]" is-image-diff="[[isImageDiff]]"
base-image="[[baseImage]]" base-image="[[baseImage]]"
plugin-layers="[[pluginLayers]]" layers="[[layers]]"
revision-image="[[revisionImage]]"> revision-image="[[revisionImage]]">
<table <table
id="diffTable" id="diffTable"

View File

@@ -271,7 +271,7 @@
/** Set by Polymer. */ /** Set by Polymer. */
isAttached: Boolean, isAttached: Boolean,
pluginLayers: Array, layers: Array,
}, },
behaviors: [ behaviors: [
@@ -724,7 +724,7 @@
_diffChanged(newValue) { _diffChanged(newValue) {
if (newValue) { if (newValue) {
this._diffLength = this.$.diffBuilder.getDiffLength(); this._diffLength = this.getDiffLength(newValue);
this._debounceRenderDiffTable(); this._debounceRenderDiffTable();
} }
}, },
@@ -766,7 +766,11 @@
this.$.diffBuilder.render(keyLocations, this._getBypassPrefs()) this.$.diffBuilder.render(keyLocations, this._getBypassPrefs())
.then(() => { .then(() => {
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('render', {bubbles: true, composed: true})); new CustomEvent('render', {
bubbles: true,
composed: true,
detail: {contentRendered: true},
}));
}); });
}, },
@@ -955,5 +959,23 @@
if (loading || !warning) { return 'newlineWarning hidden'; } if (loading || !warning) { return 'newlineWarning hidden'; }
return 'newlineWarning'; return 'newlineWarning';
}, },
/**
* Get the approximate length of the diff as the sum of the maximum
* length of the chunks.
* @param {Object} diff object
* @return {number}
*/
getDiffLength(diff) {
return diff.content.reduce((sum, sec) => {
if (sec.hasOwnProperty('ab')) {
return sum + sec.ab.length;
} else {
return sum + Math.max(
sec.hasOwnProperty('a') ? sec.a.length : 0,
sec.hasOwnProperty('b') ? sec.b.length : 0);
}
}, 0);
},
}); });
})(); })();

View File

@@ -767,7 +767,7 @@ limitations under the License.
new CustomEvent('render', {bubbles: true, composed: true})); new CustomEvent('render', {bubbles: true, composed: true}));
}); });
const mock = document.createElement('mock-diff-response'); const mock = document.createElement('mock-diff-response');
sandbox.stub(element.$.diffBuilder, 'getDiffLength').returns(10000); sandbox.stub(element, 'getDiffLength').returns(10000);
element.diff = mock.diffResponse; element.diff = mock.diffResponse;
element.noRenderOnPrefsChange = true; element.noRenderOnPrefsChange = true;
}); });
@@ -1101,6 +1101,23 @@ limitations under the License.
)); ));
}); });
}); });
test('getDiffLength', () => {
const diff = document.createElement('mock-diff-response').diffResponse;
assert.equal(element.getDiffLength(diff), 52);
});
test('`render` event has contentRendered field in detail', done => {
element = fixture('basic');
element.prefs = {};
renderStub = sandbox.stub(element.$.diffBuilder, 'render')
.returns(Promise.resolve());
element.addEventListener('render', event => {
assert.isTrue(event.detail.contentRendered);
done();
});
element._renderDiffTable();
});
}); });
a11ySuite('basic'); a11ySuite('basic');

View File

@@ -225,7 +225,7 @@
process() { process() {
// Cancel any still running process() calls, because they append to the // Cancel any still running process() calls, because they append to the
// same _baseRanges and _revisionRanges fields. // same _baseRanges and _revisionRanges fields.
this.cancel(); this._cancel();
// Discard existing ranges. // Discard existing ranges.
this._baseRanges = []; this._baseRanges = [];
@@ -295,7 +295,7 @@
/** /**
* Cancel any asynchronous syntax processing jobs. * Cancel any asynchronous syntax processing jobs.
*/ */
cancel() { _cancel() {
if (this._processHandle != null) { if (this._processHandle != null) {
this.cancelAsync(this._processHandle); this.cancelAsync(this._processHandle);
this._processHandle = null; this._processHandle = null;
@@ -306,7 +306,7 @@
}, },
_diffChanged() { _diffChanged() {
this.cancel(); this._cancel();
this._baseRanges = []; this._baseRanges = [];
this._revisionRanges = []; this._revisionRanges = [];
}, },