
These tags are preserved by the Closure compiler and vulcanize in order to serve the license notices embedded in the outputs. In a standalone Gerrit server, these license are also covered in the LICENSES.txt served with the documentation. When serving PG assets from a CDN, it's less obvious what the corresponding LICENSES.txt file is, since the CDN is not directly linked to a running Gerrit server. Safer to embed the licenses in the assets themselves. Change-Id: Id1add1451fad1baa7916882a6bda02c326ccc988
281 lines
9.1 KiB
HTML
281 lines
9.1 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
@license
|
|
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-cursor-manager</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-cursor-manager.html">
|
|
|
|
<script>void(0);</script>
|
|
|
|
<test-fixture id="basic">
|
|
<template>
|
|
<gr-cursor-manager cursor-target-class="targeted"></gr-cursor-manager>
|
|
<ul>
|
|
<li>A</li>
|
|
<li>B</li>
|
|
<li>C</li>
|
|
<li>D</li>
|
|
</ul>
|
|
</template>
|
|
</test-fixture>
|
|
|
|
<script>
|
|
suite('gr-cursor-manager tests', () => {
|
|
let sandbox;
|
|
let element;
|
|
let list;
|
|
|
|
setup(() => {
|
|
sandbox = sinon.sandbox.create();
|
|
const fixtureElements = fixture('basic');
|
|
element = fixtureElements[0];
|
|
list = fixtureElements[1];
|
|
});
|
|
|
|
teardown(() => {
|
|
sandbox.restore();
|
|
});
|
|
|
|
test('core cursor functionality', () => {
|
|
// The element is initialized into the proper state.
|
|
assert.isArray(element.stops);
|
|
assert.equal(element.stops.length, 0);
|
|
assert.equal(element.index, -1);
|
|
assert.isNotOk(element.target);
|
|
|
|
// Initialize the cursor with its stops.
|
|
element.stops = list.querySelectorAll('li');
|
|
|
|
// It should have the stops but it should not be targeting any of them.
|
|
assert.isNotNull(element.stops);
|
|
assert.equal(element.stops.length, 4);
|
|
assert.equal(element.index, -1);
|
|
assert.isNotOk(element.target);
|
|
|
|
// Select the third stop.
|
|
element.setCursor(list.children[2]);
|
|
|
|
// It should update its internal state and update the element's class.
|
|
assert.equal(element.index, 2);
|
|
assert.equal(element.target, list.children[2]);
|
|
assert.isTrue(list.children[2].classList.contains('targeted'));
|
|
assert.isFalse(element.isAtStart());
|
|
assert.isFalse(element.isAtEnd());
|
|
|
|
// Progress the cursor.
|
|
element.next();
|
|
|
|
// Confirm that the next stop is selected and that the previous stop is
|
|
// unselected.
|
|
assert.equal(element.index, 3);
|
|
assert.equal(element.target, list.children[3]);
|
|
assert.isTrue(element.isAtEnd());
|
|
assert.isFalse(list.children[2].classList.contains('targeted'));
|
|
assert.isTrue(list.children[3].classList.contains('targeted'));
|
|
|
|
// Progress the cursor.
|
|
element.next();
|
|
|
|
// We should still be at the end.
|
|
assert.equal(element.index, 3);
|
|
assert.equal(element.target, list.children[3]);
|
|
assert.isTrue(element.isAtEnd());
|
|
|
|
// Wind the cursor all the way back to the first stop.
|
|
element.previous();
|
|
element.previous();
|
|
element.previous();
|
|
|
|
// The element state should reflect the end of the list.
|
|
assert.equal(element.index, 0);
|
|
assert.equal(element.target, list.children[0]);
|
|
assert.isTrue(element.isAtStart());
|
|
assert.isTrue(list.children[0].classList.contains('targeted'));
|
|
|
|
const newLi = document.createElement('li');
|
|
newLi.textContent = 'Z';
|
|
list.insertBefore(newLi, list.children[0]);
|
|
element.stops = list.querySelectorAll('li');
|
|
|
|
assert.equal(element.index, 1);
|
|
|
|
// De-select all targets.
|
|
element.unsetCursor();
|
|
|
|
// There should now be no cursor target.
|
|
assert.isFalse(list.children[1].classList.contains('targeted'));
|
|
assert.isNotOk(element.target);
|
|
assert.equal(element.index, -1);
|
|
});
|
|
|
|
|
|
test('_moveCursor', () => {
|
|
// Initialize the cursor with its stops.
|
|
element.stops = list.querySelectorAll('li');
|
|
// Select the first stop.
|
|
element.setCursor(list.children[0]);
|
|
const getTargetHeight = sinon.stub();
|
|
|
|
// Move the cursor without an optional get target height function.
|
|
element._moveCursor(1);
|
|
assert.isFalse(getTargetHeight.called);
|
|
|
|
// Move the cursor with an optional get target height function.
|
|
element._moveCursor(1, null, getTargetHeight);
|
|
assert.isTrue(getTargetHeight.called);
|
|
});
|
|
|
|
test('_moveCursor from -1 does not check height', () => {
|
|
element.stops = list.querySelectorAll('li');
|
|
const getTargetHeight = sinon.stub();
|
|
element._moveCursor(1, () => false, getTargetHeight);
|
|
assert.isFalse(getTargetHeight.called);
|
|
});
|
|
|
|
test('opt_noScroll', () => {
|
|
sandbox.stub(element, '_targetIsVisible', () => false);
|
|
const scrollStub = sandbox.stub(window, 'scrollTo');
|
|
element.stops = list.querySelectorAll('li');
|
|
element.scrollBehavior = 'keep-visible';
|
|
|
|
element.setCursorAtIndex(1, true);
|
|
assert.isFalse(scrollStub.called);
|
|
|
|
element.setCursorAtIndex(2);
|
|
assert.isTrue(scrollStub.called);
|
|
});
|
|
|
|
test('_getNextindex', () => {
|
|
const isLetterB = function(row) {
|
|
return row.textContent === 'B';
|
|
};
|
|
element.stops = list.querySelectorAll('li');
|
|
// Start cursor at the first stop.
|
|
element.setCursor(list.children[0]);
|
|
|
|
// Move forward to meet the next condition.
|
|
assert.equal(element._getNextindex(1, isLetterB), 1);
|
|
element.index = 1;
|
|
|
|
// Nothing else meets the condition, should be at last stop.
|
|
assert.equal(element._getNextindex(1, isLetterB), 3);
|
|
element.index = 3;
|
|
|
|
// Should stay at last stop if try to proceed.
|
|
assert.equal(element._getNextindex(1, isLetterB), 3);
|
|
|
|
// Go back to the previous condition met. Should be back at.
|
|
// stop 1.
|
|
assert.equal(element._getNextindex(-1, isLetterB), 1);
|
|
element.index = 1;
|
|
|
|
// Go back. No more meet the condition. Should be at stop 0.
|
|
assert.equal(element._getNextindex(-1, isLetterB), 0);
|
|
});
|
|
|
|
test('focusOnMove prop', () => {
|
|
const listEls = list.querySelectorAll('li');
|
|
for (let i = 0; i < listEls.length; i++) {
|
|
sandbox.spy(listEls[i], 'focus');
|
|
}
|
|
element.stops = listEls;
|
|
element.setCursor(list.children[0]);
|
|
|
|
element.focusOnMove = false;
|
|
element.next();
|
|
assert.isFalse(element.target.focus.called);
|
|
|
|
element.focusOnMove = true;
|
|
element.next();
|
|
assert.isTrue(element.target.focus.called);
|
|
});
|
|
|
|
suite('_scrollToTarget', () => {
|
|
let scrollStub;
|
|
setup(() => {
|
|
element.stops = list.querySelectorAll('li');
|
|
element.scrollBehavior = 'keep-visible';
|
|
|
|
// There is a target which has a targetNext
|
|
element.setCursor(list.children[0]);
|
|
element._moveCursor(1);
|
|
scrollStub = sandbox.stub(window, 'scrollTo');
|
|
window.innerHeight = 60;
|
|
});
|
|
|
|
test('Called when top and bottom not visible', () => {
|
|
sandbox.stub(element, '_targetIsVisible').returns(false);
|
|
element._scrollToTarget();
|
|
assert.isTrue(scrollStub.called);
|
|
});
|
|
|
|
test('Not called when top and bottom visible', () => {
|
|
sandbox.stub(element, '_targetIsVisible').returns(true);
|
|
element._scrollToTarget();
|
|
assert.isFalse(scrollStub.called);
|
|
});
|
|
|
|
test('Called when top is visible, bottom is not, scroll is lower', () => {
|
|
const visibleStub = sandbox.stub(element, '_targetIsVisible',
|
|
() => visibleStub.callCount === 2);
|
|
sandbox.stub(element, '_getWindowDims').returns({
|
|
scrollX: 123,
|
|
scrollY: 15,
|
|
innerHeight: 1000,
|
|
pageYOffset: 0,
|
|
});
|
|
sandbox.stub(element, '_calculateScrollToValue').returns(20);
|
|
element._scrollToTarget();
|
|
assert.isTrue(scrollStub.called);
|
|
assert.isTrue(scrollStub.calledWithExactly(123, 20));
|
|
assert.equal(visibleStub.callCount, 2);
|
|
});
|
|
|
|
test('Called when top is visible, bottom not, scroll is higher', () => {
|
|
const visibleStub = sandbox.stub(element, '_targetIsVisible',
|
|
() => visibleStub.callCount === 2);
|
|
sandbox.stub(element, '_getWindowDims').returns({
|
|
scrollX: 123,
|
|
scrollY: 25,
|
|
innerHeight: 1000,
|
|
pageYOffset: 0,
|
|
});
|
|
sandbox.stub(element, '_calculateScrollToValue').returns(20);
|
|
element._scrollToTarget();
|
|
assert.isFalse(scrollStub.called);
|
|
assert.equal(visibleStub.callCount, 2);
|
|
});
|
|
|
|
test('_calculateScrollToValue', () => {
|
|
sandbox.stub(element, '_getWindowDims').returns({
|
|
scrollX: 123,
|
|
scrollY: 25,
|
|
innerHeight: 300,
|
|
pageYOffset: 0,
|
|
});
|
|
assert.equal(element._calculateScrollToValue(1000, {offsetHeight: 10}),
|
|
905);
|
|
});
|
|
});
|
|
});
|
|
</script>
|