
In the file list, divs are displayed as block elements, so that their contents can be scrollable. It's impossible to fix this with a z-index. Instead, this change shows the tooltip below rather than above in the case that the first line is part of the selection range. Bug: Issue 7320 Change-Id: I29a4ebc619cd0a5523fb4900abccb491cf9a5194
630 lines
24 KiB
HTML
630 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Copyright (C) 2016 The Android Open Source Project
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
-->
|
|
|
|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
|
<title>gr-diff-highlight</title>
|
|
|
|
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
|
|
<script src="../../../bower_components/web-component-tester/browser.js"></script>
|
|
<link rel="import" href="../../../test/common-test-setup.html"/>
|
|
<link rel="import" href="gr-diff-highlight.html">
|
|
|
|
<script>void(0);</script>
|
|
|
|
<test-fixture id="basic">
|
|
<template>
|
|
<style>
|
|
.tab-indicator:before {
|
|
color: #C62828;
|
|
/* >> character */
|
|
content: '\00BB';
|
|
}
|
|
</style>
|
|
<gr-diff-highlight>
|
|
<table id="diffTable">
|
|
|
|
<tbody class="section both">
|
|
<tr class="diff-row side-by-side" left-type="both" right-type="both">
|
|
<td class="left lineNum" data-value="1"></td>
|
|
<td class="content both"><div class="contentText">[1] Nam cum ad me in Cumanum salutandi causa uterque venisset,</div></td>
|
|
<td class="right lineNum" data-value="1"></td>
|
|
<td class="content both"><div class="contentText">[1] Nam cum ad me in Cumanum salutandi causa uterque</div></td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
<tbody class="section delta">
|
|
<tr class="diff-row side-by-side" left-type="remove" right-type="add">
|
|
<td class="left lineNum" data-value="2"></td>
|
|
<!-- Next tag is formatted to eliminate zero-length text nodes. -->
|
|
<td class="content remove"><div class="contentText">na💢ti <hl class="foo">te, inquit</hl>, sumus <hl class="bar">aliquando</hl> otiosum, <hl>certe</hl> a <hl><span class="tab-indicator" style="tab-size:8;"> </span></hl>udiam, <hl>quid</hl> sit, <span class="tab-indicator" style="tab-size:8;"> </span>quod <hl>Epicurum</hl></div></td>
|
|
<td class="right lineNum" data-value="2"></td>
|
|
<!-- Next tag is formatted to eliminate zero-length text nodes. -->
|
|
<td class="content add"><div class="contentText">nacti , <hl>,</hl> sumus <hl><span class="tab-indicator" style="tab-size:8;"> </span></hl> otiosum, <span class="tab-indicator" style="tab-size:8;"> </span> audiam, sit, quod</div></td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
|
|
<tbody class="section both">
|
|
<tr class="diff-row side-by-side" left-type="both" right-type="both">
|
|
<td class="left lineNum" data-value="138"></td>
|
|
<td class="content both"><div class="contentText">[14] Nam cum ad me in Cumanum salutandi causa uterque venisset,</div></td>
|
|
<td class="right lineNum" data-value="119"></td>
|
|
<td class="content both"><div class="contentText">[14] Nam cum ad me in Cumanum salutandi causa uterque venisset,</div></td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
<tbody class="section delta">
|
|
<tr class="diff-row side-by-side" left-type="remove" right-type="add">
|
|
<td class="left lineNum" data-value="140"></td>
|
|
<!-- Next tag is formatted to eliminate zero-length text nodes. -->
|
|
<td class="content remove"><div class="contentText">na💢ti <hl class="foo">te, inquit</hl>, sumus <hl class="bar">aliquando</hl> otiosum, <hl>certe</hl> a <hl><span class="tab-indicator" style="tab-size:8;"> </span></hl>udiam, <hl>quid</hl> sit, <span class="tab-indicator" style="tab-size:8;"> </span>quod <hl>Epicurum</hl></div><gr-diff-comment-thread>
|
|
[Yet another random diff thread content here]
|
|
</gr-diff-comment-thread></td>
|
|
<td class="right lineNum" data-value="120"></td>
|
|
<!-- Next tag is formatted to eliminate zero-length text nodes. -->
|
|
<td class="content add"><div class="contentText">nacti , <hl>,</hl> sumus <hl><span class="tab-indicator" style="tab-size:8;"> </span></hl> otiosum, <span class="tab-indicator" style="tab-size:8;"> </span> audiam, sit, quod</div></td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
<tbody class="section both">
|
|
<tr class="diff-row side-by-side" left-type="both" right-type="both">
|
|
<td class="left lineNum" data-value="141"></td>
|
|
<td class="content both"><div class="contentText">nam et<hl><span class="tab-indicator" style="tab-size:8;"> </span></hl>complectitur<span class="tab-indicator" style="tab-size:8;"> </span>verbis, quod vult, et dicit plane, quod intellegam;</div></td>
|
|
<td class="right lineNum" data-value="130"></td>
|
|
<td class="content both"><div class="contentText">nam et complectitur verbis, quod vult, et dicit plane, quod intellegam;</div></td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
<tbody class="section contextControl">
|
|
<tr class="diff-row side-by-side" left-type="contextControl" right-type="contextControl">
|
|
<td class="left contextLineNum" data-value="@@"></td>
|
|
<td>
|
|
<gr-button>+10↑</gr-button>
|
|
-
|
|
<gr-button>Show 21 common lines</gr-button>
|
|
-
|
|
<gr-button>+10↓</gr-button>
|
|
</td>
|
|
<td class="right contextLineNum" data-value="@@"></td>
|
|
<td>
|
|
<gr-button>+10↑</gr-button>
|
|
-
|
|
<gr-button>Show 21 common lines</gr-button>
|
|
-
|
|
<gr-button>+10↓</gr-button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
<tbody class="section delta total">
|
|
<tr class="diff-row side-by-side" left-type="blank" right-type="add">
|
|
<td class="left"></td>
|
|
<td class="blank"></td>
|
|
<td class="right lineNum" data-value="146"></td>
|
|
<td class="content add"><div class="contentText">[17] Quid igitur est? inquit; audire enim cupio, quid non probes. Principio, inquam,</div></td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
<tbody class="section both">
|
|
<tr class="diff-row side-by-side" left-type="both" right-type="both">
|
|
<td class="left lineNum" data-value="165"></td>
|
|
<td class="content both"><div class="contentText">in physicis, quibus maxime gloriatur, primum totus est alienus. Democritea dicit</div></td>
|
|
<td class="right lineNum" data-value="147"></td>
|
|
<td class="content both"><div class="contentText">in physicis, <hl><span class="tab-indicator" style="tab-size:8;"> </span></hl> quibus maxime gloriatur, primum totus est alienus. Democritea dicit</div></td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
</table>
|
|
</gr-diff-highlight>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<test-fixture id="highlighted">
|
|
<template>
|
|
<div>
|
|
<hl class="rangeHighlight">foo</hl>
|
|
bar
|
|
<hl class="rangeHighlight">baz</hl>
|
|
</div>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<script>
|
|
suite('gr-diff-highlight', () => {
|
|
let element;
|
|
let sandbox;
|
|
|
|
setup(() => {
|
|
sandbox = sinon.sandbox.create();
|
|
element = fixture('basic')[1];
|
|
});
|
|
|
|
teardown(() => {
|
|
sandbox.restore();
|
|
});
|
|
|
|
suite('selectionchange event handling', () => {
|
|
const emulateSelection = function() {
|
|
document.dispatchEvent(new CustomEvent('selectionchange'));
|
|
element.flushDebouncer('selectionChange');
|
|
element.flushDebouncer('removeActionBox');
|
|
};
|
|
|
|
setup(() => {
|
|
sandbox.stub(element, '_handleSelection');
|
|
sandbox.stub(element, '_removeActionBox');
|
|
});
|
|
|
|
test('enabled if logged in', () => {
|
|
element.loggedIn = true;
|
|
emulateSelection();
|
|
assert.isTrue(element._handleSelection.called);
|
|
assert.isTrue(element._removeActionBox.called);
|
|
});
|
|
|
|
test('ignored if logged out', () => {
|
|
element.loggedIn = false;
|
|
emulateSelection();
|
|
assert.isFalse(element._handleSelection.called);
|
|
assert.isFalse(element._removeActionBox.called);
|
|
});
|
|
});
|
|
|
|
suite('comment events', () => {
|
|
let builder;
|
|
|
|
setup(() => {
|
|
builder = {
|
|
getContentsByLineRange: sandbox.stub().returns([]),
|
|
getLineElByChild: sandbox.stub().returns({}),
|
|
getSideByLineEl: sandbox.stub().returns('other-side'),
|
|
};
|
|
element._cachedDiffBuilder = builder;
|
|
});
|
|
|
|
test('comment-mouse-over from line comments is ignored', () => {
|
|
sandbox.stub(element, 'set');
|
|
element.fire('comment-mouse-over', {comment: {}});
|
|
assert.isFalse(element.set.called);
|
|
});
|
|
|
|
test('comment-mouse-over from ranged comment causes set', () => {
|
|
sandbox.stub(element, 'set');
|
|
sandbox.stub(element, '_indexOfComment').returns(0);
|
|
element.fire('comment-mouse-over', {comment: {range: {}}});
|
|
assert.isTrue(element.set.called);
|
|
});
|
|
|
|
test('comment-mouse-out from line comments is ignored', () => {
|
|
element.fire('comment-mouse-over', {comment: {}});
|
|
assert.isFalse(builder.getContentsByLineRange.called);
|
|
});
|
|
|
|
test('on create-comment action box is removed', () => {
|
|
sandbox.stub(element, '_removeActionBox');
|
|
element.fire('create-comment', {
|
|
comment: {
|
|
range: {},
|
|
},
|
|
});
|
|
assert.isTrue(element._removeActionBox.called);
|
|
});
|
|
});
|
|
|
|
suite('selection', () => {
|
|
let diff;
|
|
let builder;
|
|
let contentStubs;
|
|
|
|
const stubContent = (line, side, opt_child) => {
|
|
const contentTd = diff.querySelector(
|
|
`.${side}.lineNum[data-value="${line}"] ~ .content`);
|
|
const contentText = contentTd.querySelector('.contentText');
|
|
const lineEl = diff.querySelector(
|
|
`.${side}.lineNum[data-value="${line}"]`);
|
|
contentStubs.push({
|
|
lineEl,
|
|
contentTd,
|
|
contentText,
|
|
});
|
|
builder.getContentByLineEl.withArgs(lineEl).returns(contentText);
|
|
builder.getLineNumberByChild.withArgs(lineEl).returns(line);
|
|
builder.getContentByLine.withArgs(line, side).returns(contentText);
|
|
builder.getSideByLineEl.withArgs(lineEl).returns(side);
|
|
return contentText;
|
|
};
|
|
|
|
const emulateSelection = (startNode, startOffset, endNode, endOffset) => {
|
|
const selection = window.getSelection();
|
|
const range = document.createRange();
|
|
range.setStart(startNode, startOffset);
|
|
range.setEnd(endNode, endOffset);
|
|
selection.addRange(range);
|
|
element._handleSelection();
|
|
};
|
|
|
|
const getActionRange = () =>
|
|
Polymer.dom(element.root).querySelector(
|
|
'gr-selection-action-box').range;
|
|
|
|
const getActionSide = () =>
|
|
Polymer.dom(element.root).querySelector(
|
|
'gr-selection-action-box').side;
|
|
|
|
const getLineElByChild = node => {
|
|
const stubs = contentStubs.find(stub => stub.contentTd.contains(node));
|
|
return stubs && stubs.lineEl;
|
|
};
|
|
|
|
setup(() => {
|
|
contentStubs = [];
|
|
stub('gr-selection-action-box', {
|
|
placeAbove: sandbox.stub(),
|
|
placeBelow: sandbox.stub(),
|
|
});
|
|
diff = element.querySelector('#diffTable');
|
|
builder = {
|
|
getContentByLine: sandbox.stub(),
|
|
getContentByLineEl: sandbox.stub(),
|
|
getLineElByChild,
|
|
getLineNumberByChild: sandbox.stub(),
|
|
getSideByLineEl: sandbox.stub(),
|
|
};
|
|
element._cachedDiffBuilder = builder;
|
|
});
|
|
|
|
teardown(() => {
|
|
contentStubs = null;
|
|
window.getSelection().removeAllRanges();
|
|
});
|
|
|
|
test('single first line', () => {
|
|
const content = stubContent(1, 'right');
|
|
sandbox.spy(element, '_positionActionBox');
|
|
emulateSelection(content.firstChild, 5, content.firstChild, 12);
|
|
const actionBox = element.$$('gr-selection-action-box');
|
|
assert.isTrue(actionBox.positionBelow);
|
|
});
|
|
|
|
test('multiline starting on first line', () => {
|
|
const startContent = stubContent(1, 'right');
|
|
const endContent = stubContent(2, 'right');
|
|
sandbox.spy(element, '_positionActionBox');
|
|
emulateSelection(
|
|
startContent.firstChild, 10, endContent.lastChild, 7);
|
|
const actionBox = element.$$('gr-selection-action-box');
|
|
assert.isTrue(actionBox.positionBelow);
|
|
});
|
|
|
|
test('single line', () => {
|
|
const content = stubContent(138, 'left');
|
|
sandbox.spy(element, '_positionActionBox');
|
|
emulateSelection(content.firstChild, 5, content.firstChild, 12);
|
|
const actionBox = element.$$('gr-selection-action-box');
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 138,
|
|
startChar: 5,
|
|
endLine: 138,
|
|
endChar: 12,
|
|
});
|
|
assert.equal(getActionSide(), 'left');
|
|
assert.notOk(actionBox.positionBelow);
|
|
});
|
|
|
|
test('multiline', () => {
|
|
const startContent = stubContent(119, 'right');
|
|
const endContent = stubContent(120, 'right');
|
|
sandbox.spy(element, '_positionActionBox');
|
|
emulateSelection(
|
|
startContent.firstChild, 10, endContent.lastChild, 7);
|
|
assert.isTrue(element.isRangeSelected());
|
|
const actionBox = element.$$('gr-selection-action-box');
|
|
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 119,
|
|
startChar: 10,
|
|
endLine: 120,
|
|
endChar: 36,
|
|
});
|
|
assert.equal(getActionSide(), 'right');
|
|
assert.notOk(actionBox.positionBelow);
|
|
});
|
|
|
|
test('multiple ranges aka firefox implementation', () => {
|
|
const startContent = stubContent(119, 'right');
|
|
const endContent = stubContent(120, 'right');
|
|
|
|
const startRange = document.createRange();
|
|
startRange.setStart(startContent.firstChild, 10);
|
|
startRange.setEnd(startContent.firstChild, 11);
|
|
|
|
const endRange = document.createRange();
|
|
endRange.setStart(endContent.lastChild, 6);
|
|
endRange.setEnd(endContent.lastChild, 7);
|
|
|
|
const getRangeAtStub = sandbox.stub();
|
|
getRangeAtStub
|
|
.onFirstCall().returns(startRange)
|
|
.onSecondCall().returns(endRange);
|
|
sandbox.stub(window, 'getSelection').returns({
|
|
rangeCount: 2,
|
|
getRangeAt: getRangeAtStub,
|
|
removeAllRanges: sandbox.stub(),
|
|
});
|
|
element._handleSelection();
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 119,
|
|
startChar: 10,
|
|
endLine: 120,
|
|
endChar: 36,
|
|
});
|
|
});
|
|
|
|
test('multiline grow end highlight over tabs', () => {
|
|
const startContent = stubContent(119, 'right');
|
|
const endContent = stubContent(120, 'right');
|
|
emulateSelection(startContent.firstChild, 10, endContent.firstChild, 2);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 119,
|
|
startChar: 10,
|
|
endLine: 120,
|
|
endChar: 2,
|
|
});
|
|
assert.equal(getActionSide(), 'right');
|
|
});
|
|
|
|
test('collapsed', () => {
|
|
const content = stubContent(138, 'left');
|
|
emulateSelection(content.firstChild, 5, content.firstChild, 5);
|
|
assert.isOk(window.getSelection().getRangeAt(0).startContainer);
|
|
assert.isFalse(element.isRangeSelected());
|
|
});
|
|
|
|
test('starts inside hl', () => {
|
|
const content = stubContent(140, 'left');
|
|
const hl = content.querySelector('.foo');
|
|
emulateSelection(hl.firstChild, 2, hl.nextSibling, 7);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 140,
|
|
startChar: 8,
|
|
endLine: 140,
|
|
endChar: 23,
|
|
});
|
|
assert.equal(getActionSide(), 'left');
|
|
});
|
|
|
|
test('ends inside hl', () => {
|
|
const content = stubContent(140, 'left');
|
|
const hl = content.querySelector('.bar');
|
|
emulateSelection(hl.previousSibling, 2, hl.firstChild, 3);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 140,
|
|
startChar: 18,
|
|
endLine: 140,
|
|
endChar: 27,
|
|
});
|
|
});
|
|
|
|
test('multiple hl', () => {
|
|
const content = stubContent(140, 'left');
|
|
const hl = content.querySelectorAll('hl')[4];
|
|
emulateSelection(content.firstChild, 2, hl.firstChild, 2);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 140,
|
|
startChar: 2,
|
|
endLine: 140,
|
|
endChar: 61,
|
|
});
|
|
assert.equal(getActionSide(), 'left');
|
|
});
|
|
|
|
test('starts outside of diff', () => {
|
|
const contentText = stubContent(140, 'left');
|
|
const contentTd = contentText.parentElement;
|
|
|
|
emulateSelection(contentTd.previousElementSibling, 0,
|
|
contentText.firstChild, 2);
|
|
assert.isFalse(element.isRangeSelected());
|
|
});
|
|
|
|
test('ends outside of diff', () => {
|
|
const content = stubContent(140, 'left');
|
|
emulateSelection(content.nextElementSibling.firstChild, 2,
|
|
content.firstChild, 2);
|
|
assert.isFalse(element.isRangeSelected());
|
|
});
|
|
|
|
test('starts and ends on different sides', () => {
|
|
const startContent = stubContent(140, 'left');
|
|
const endContent = stubContent(130, 'right');
|
|
emulateSelection(startContent.firstChild, 2, endContent.firstChild, 2);
|
|
assert.isFalse(element.isRangeSelected());
|
|
});
|
|
|
|
test('starts in comment thread element', () => {
|
|
const startContent = stubContent(140, 'left');
|
|
const comment = startContent.parentElement.querySelector(
|
|
'gr-diff-comment-thread');
|
|
const endContent = stubContent(141, 'left');
|
|
emulateSelection(comment.firstChild, 2, endContent.firstChild, 4);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 140,
|
|
startChar: 83,
|
|
endLine: 141,
|
|
endChar: 4,
|
|
});
|
|
assert.equal(getActionSide(), 'left');
|
|
});
|
|
|
|
test('ends in comment thread element', () => {
|
|
const content = stubContent(140, 'left');
|
|
const comment = content.parentElement.querySelector(
|
|
'gr-diff-comment-thread');
|
|
emulateSelection(content.firstChild, 4, comment.firstChild, 1);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 140,
|
|
startChar: 4,
|
|
endLine: 140,
|
|
endChar: 83,
|
|
});
|
|
assert.equal(getActionSide(), 'left');
|
|
});
|
|
|
|
test('starts in context element', () => {
|
|
const contextControl =
|
|
diff.querySelector('.contextControl').querySelector('gr-button');
|
|
const content = stubContent(146, 'right');
|
|
emulateSelection(contextControl, 0, content.firstChild, 7);
|
|
// TODO (viktard): Select nearest line.
|
|
assert.isFalse(element.isRangeSelected());
|
|
});
|
|
|
|
test('ends in context element', () => {
|
|
const contextControl =
|
|
diff.querySelector('.contextControl').querySelector('gr-button');
|
|
const content = stubContent(141, 'left');
|
|
emulateSelection(content.firstChild, 2, contextControl, 1);
|
|
// TODO (viktard): Select nearest line.
|
|
assert.isFalse(element.isRangeSelected());
|
|
});
|
|
|
|
test('selection containing context element', () => {
|
|
const startContent = stubContent(130, 'right');
|
|
const endContent = stubContent(146, 'right');
|
|
emulateSelection(startContent.firstChild, 3, endContent.firstChild, 14);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 130,
|
|
startChar: 3,
|
|
endLine: 146,
|
|
endChar: 14,
|
|
});
|
|
assert.equal(getActionSide(), 'right');
|
|
});
|
|
|
|
test('ends at a tab', () => {
|
|
const content = stubContent(140, 'left');
|
|
emulateSelection(
|
|
content.firstChild, 1, content.querySelector('span'), 0);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 140,
|
|
startChar: 1,
|
|
endLine: 140,
|
|
endChar: 51,
|
|
});
|
|
assert.equal(getActionSide(), 'left');
|
|
});
|
|
|
|
test('starts at a tab', () => {
|
|
const content = stubContent(140, 'left');
|
|
emulateSelection(
|
|
content.querySelectorAll('hl')[3], 0,
|
|
content.querySelectorAll('span')[1].nextSibling, 1);
|
|
assert.isTrue(element.isRangeSelected());
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 140,
|
|
startChar: 51,
|
|
endLine: 140,
|
|
endChar: 71,
|
|
});
|
|
assert.equal(getActionSide(), 'left');
|
|
});
|
|
|
|
test('properly accounts for syntax highlighting', () => {
|
|
const content = stubContent(140, 'left');
|
|
const spy = sinon.spy(element, '_normalizeRange');
|
|
emulateSelection(
|
|
content.querySelectorAll('hl')[3], 0,
|
|
content.querySelectorAll('span')[1], 0);
|
|
const spyCall = spy.getCall(0);
|
|
const range = window.getSelection().getRangeAt(0);
|
|
assert.notDeepEqual(spyCall.returnValue, range);
|
|
});
|
|
|
|
test('GrRangeNormalizer._getTextOffset computes text offset', () => {
|
|
let content = stubContent(140, 'left');
|
|
let child = content.lastChild.lastChild;
|
|
let result = GrRangeNormalizer._getTextOffset(content, child);
|
|
assert.equal(result, 75);
|
|
content = stubContent(146, 'right');
|
|
child = content.lastChild;
|
|
result = GrRangeNormalizer._getTextOffset(content, child);
|
|
assert.equal(result, 0);
|
|
});
|
|
|
|
// TODO (viktard): Selection starts in line number.
|
|
// TODO (viktard): Empty lines in selection start.
|
|
// TODO (viktard): Empty lines in selection end.
|
|
// TODO (viktard): Only empty lines selected.
|
|
// TODO (viktard): Unified mode.
|
|
|
|
suite('triple click', () => {
|
|
test('_fixTripleClickSelection', () => {
|
|
const fakeRange = {
|
|
startContainer: '',
|
|
startOffset: '',
|
|
endContainer: '',
|
|
endOffset: '',
|
|
};
|
|
const fixedRange = {};
|
|
sandbox.stub(GrRangeNormalizer, 'normalize').returns(fakeRange);
|
|
sandbox.stub(element, '_normalizeSelectionSide');
|
|
sandbox.stub(element, '_fixTripleClickSelection').returns(fixedRange);
|
|
assert.strictEqual(element._normalizeRange({}), fixedRange);
|
|
assert.isTrue(element._fixTripleClickSelection.called);
|
|
});
|
|
|
|
test('left pane', () => {
|
|
const startNode = stubContent(138, 'left');
|
|
const endNode =
|
|
stubContent(119, 'right').parentElement.previousElementSibling;
|
|
builder.getLineNumberByChild.withArgs(endNode).returns(119);
|
|
emulateSelection(startNode, 0, endNode, 0);
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 138,
|
|
startChar: 0,
|
|
endLine: 138,
|
|
endChar: 63,
|
|
});
|
|
});
|
|
|
|
test('right pane', () => {
|
|
const startNode = stubContent(119, 'right');
|
|
const endNode =
|
|
stubContent(140, 'left').parentElement.previousElementSibling;
|
|
emulateSelection(startNode, 0, endNode, 0);
|
|
assert.deepEqual(getActionRange(), {
|
|
startLine: 119,
|
|
startChar: 0,
|
|
endLine: 119,
|
|
endChar: 63,
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
</script>
|