Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,252 @@
'use strict';
/* global AlternativesCharMenuView */
require('/js/views/alternatives_char_menu_view.js');
require('/js/views/key_view.js');
suite('Views > AlternativesCharMenuView', function() {
var menu = null;
var options = {
};
var KEY_WIDTH = 30;
var KEY_HEIGHT = 20;
var altChars = ['a', 'b', 'c'];
var fakeMenu;
var rootElement = document.createElement('div');
document.body.appendChild(rootElement);
var dummyKeyElement = document.createElement('button');
var viewManager = {
registerView: sinon.stub()
};
suite('basic show/hide testing', function() {
setup(function() {
menu = new AlternativesCharMenuView(rootElement, altChars, options,
viewManager);
});
test(' > show()', function() {
menu.show(dummyKeyElement);
assert.equal(rootElement.firstElementChild,
menu.getMenuContainer(),
'Menu was not inserted into root Element');
menu.hide();
});
test(' > hide()', function() {
menu.show(dummyKeyElement);
menu.hide();
assert.equal(rootElement.childElementCount, 0,
'Menu was not removed from root Element!');
});
});
suite(' > getMenuTarget() - single row case', function() {
setup(function() {
fakeMenu = document.createElement('div');
fakeMenu.style.position = 'absolute';
fakeMenu.style.fontSize = 0;
// insert 3 keys for 1 row
for (var i = 0; i < 3; i++) {
var child = document.createElement('div');
child.style.display = 'inline-block';
child.style.width = KEY_WIDTH + 'px';
child.style.height = KEY_HEIGHT + 'px';
fakeMenu.appendChild(child);
}
rootElement.appendChild(fakeMenu);
menu = new AlternativesCharMenuView(rootElement, altChars, options,
viewManager);
this.sinon.stub(menu, 'getMenuContainer');
menu.getMenuContainer.returns(fakeMenu);
this.sinon.stub(menu, 'getBoundingClientRect',
fakeMenu.getBoundingClientRect.bind(fakeMenu));
this.sinon.stub(menu, 'getLineHeight');
menu.getLineHeight.returns(KEY_HEIGHT);
});
teardown(function() {
menu.hide();
});
test('the first element', function() {
menu.show(dummyKeyElement);
var rect = fakeMenu.getBoundingClientRect();
var target = menu.getMenuTarget(rect.left, rect.top);
assert.equal(target, menu.altKeyTargets[0],
'Should map to the first element');
});
test('the second element', function() {
menu.show(dummyKeyElement);
var rect = fakeMenu.getBoundingClientRect();
var target = menu.getMenuTarget(fakeMenu.offsetLeft + KEY_WIDTH +
rect.left, rect.top);
assert.equal(target, menu.altKeyTargets[1],
'Should map to the second element');
});
test('the last element', function() {
menu.show(dummyKeyElement);
var rect = fakeMenu.getBoundingClientRect();
var target = menu.getMenuTarget(fakeMenu.offsetLeft +
fakeMenu.offsetWidth +
rect.left, rect.top);
assert.equal(target, menu.altKeyTargets[menu.altKeyTargets.length -1],
'Should map to the last element');
});
});
suite(' > getMenuTarget() - 2 row case', function() {
setup(function() {
fakeMenu = document.createElement('div');
fakeMenu.style.position = 'absolute';
fakeMenu.style.width = KEY_WIDTH * 3 + 'px'; // 2 row
// insert 6 keys for 2 rows
for (var i = 0; i < 6; i++) {
var child = document.createElement('div');
child.style.display = 'inline-block';
child.style.width = KEY_WIDTH + 'px';
child.style.height = KEY_HEIGHT + 'px';
fakeMenu.appendChild(child);
}
rootElement.appendChild(fakeMenu);
var altChars = ['a', 'b', 'c', 'd', 'e', 'f'];
menu = new AlternativesCharMenuView(rootElement, altChars, options,
viewManager);
this.sinon.stub(menu, 'getMenuContainer');
menu.getMenuContainer.returns(fakeMenu);
this.sinon.stub(menu, 'getBoundingClientRect',
fakeMenu.getBoundingClientRect.bind(fakeMenu));
this.sinon.stub(menu, 'getLineHeight');
menu.getLineHeight.returns(KEY_HEIGHT);
});
teardown(function() {
menu.hide();
});
test('2 row - the first element', function() {
menu.show(dummyKeyElement);
var rect = fakeMenu.getBoundingClientRect();
var target = menu.getMenuTarget(rect.left, fakeMenu.offsetTop +
fakeMenu.offsetHeight +
rect.top);
assert.equal(target, menu.altKeyTargets[0],
'Should map to the first element');
});
test('2 row - the second element', function() {
menu.show(dummyKeyElement);
var rect = fakeMenu.getBoundingClientRect();
var target = menu.getMenuTarget(fakeMenu.offsetLeft + KEY_WIDTH +
rect.left,
fakeMenu.offsetTop +
fakeMenu.offsetHeight +
rect.top);
assert.equal(target, menu.altKeyTargets[1],
'Should map to the second element');
});
test('2 row - the 4th element in the upper row', function() {
menu.show(dummyKeyElement);
var rect = fakeMenu.getBoundingClientRect();
var target = menu.getMenuTarget(rect.left, rect.top);
assert.equal(target, menu.altKeyTargets[3],
'Should map to the 4th element');
});
});
suite(' > getMenuTarget() - 2 row with one empty cell case', function() {
setup(function() {
fakeMenu = document.createElement('div');
fakeMenu.style.position = 'absolute';
fakeMenu.style.width = KEY_WIDTH * 3 + 'px'; // 2 row
// insert 5 keys for 2 rows
// (would result in 3x2 cells with top top-right one being empty)
for (var i = 0; i < 5; i++) {
var child = document.createElement('div');
child.style.display = 'inline-block';
child.style.width = KEY_WIDTH + 'px';
child.style.height = KEY_HEIGHT + 'px';
fakeMenu.appendChild(child);
}
rootElement.appendChild(fakeMenu);
var altChars = ['a', 'b', 'c', 'd', 'e'];
menu = new AlternativesCharMenuView(rootElement, altChars, options,
viewManager);
this.sinon.stub(menu, 'getMenuContainer');
menu.getMenuContainer.returns(fakeMenu);
this.sinon.stub(menu, 'getBoundingClientRect',
fakeMenu.getBoundingClientRect.bind(fakeMenu));
this.sinon.stub(menu, 'getLineHeight');
menu.getLineHeight.returns(KEY_HEIGHT);
});
teardown(function() {
menu.hide();
});
test('2 row - the empty element', function() {
menu.show(dummyKeyElement);
var rect = fakeMenu.getBoundingClientRect();
var target = menu.getMenuTarget(fakeMenu.offsetLeft + rect.left +
KEY_WIDTH * 2, rect.top);
assert.equal(target, menu.altKeyTargets[4],
'Should map to the last element');
});
});
suite(' isMenuTarget()', function() {
test('isMenuTarget() returns true', function() {
assert.isTrue(menu.isMenuTarget(menu.altKeyTargets[0]));
});
test('isMenuTarget() returns false', function() {
assert.isFalse(menu.isMenuTarget({dummy: 'dummy'}));
});
});
});

View file

@ -0,0 +1,144 @@
'use strict';
/* global CandidatePanelView */
require('/js/views/base_view.js');
require('/js/views/candidate_panel_view.js');
function createFakeCandidates(count) {
var candidates = [];
for (var i = 0; i < count; i++) {
candidates.push('' + i);
}
return candidates;
}
suite('Views > CandidatePanelView', function() {
var candidatePanelView = null;
var viewManager = {
registerView: sinon.stub(),
getRemToPx: sinon.stub().returns(10)
};
suite('some basic functions', function() {
setup(function() {
var target = {};
var options = {className: 'basic-class'};
candidatePanelView = new CandidatePanelView(target, options, viewManager);
});
test('> render() ', function() {
assert.equal(candidatePanelView.element, null);
candidatePanelView.render();
assert.notEqual(candidatePanelView.element, null);
var classList = candidatePanelView.element.classList;
assert.isTrue(classList.contains('basic-class'),
'should contain the className specified in options');
});
test('> getHeight()', function() {
assert.equal(candidatePanelView.getHeight(), 32);
});
suite('> showCandidates()', function() {
test('> show 8 candidates', function() {
candidatePanelView.render();
candidatePanelView.showCandidates(createFakeCandidates(8));
var suggestionsContainer =
candidatePanelView.element.querySelector('.suggestions-container');
assert.notEqual(suggestionsContainer, null);
var row = suggestionsContainer.querySelector('.candidate-row-first');
assert.equal(row.childNodes.length, 8);
// Should not contain the toggle button
var toggleButton =
row.querySelector('.keyboard-candidate-panel-toggle-button');
assert.equal(toggleButton, null);
});
test('> show 9 candidates', function() {
candidatePanelView.render();
candidatePanelView.showCandidates(createFakeCandidates(9));
var suggestionsContainer =
candidatePanelView.element.querySelector('.suggestions-container');
assert.notEqual(suggestionsContainer, null);
var row = suggestionsContainer.querySelector('.candidate-row-first');
assert.equal(row.childNodes.length, 8);
// Should contain the toggle button
var toggleButton = candidatePanelView.element.
querySelector('.keyboard-candidate-panel-toggle-button');
assert.notEqual(toggleButton, null);
});
test('> candidates with different length', function() {
candidatePanelView.render();
var candidates = ['1', '2', '3' , '4', '55', '6', '7', '8'];
candidatePanelView.showCandidates(candidates);
var suggestionsContainer =
candidatePanelView.element.querySelector('.suggestions-container');
assert.notEqual(suggestionsContainer, null);
var row = suggestionsContainer.querySelector('.candidate-row-first');
assert.equal(row.childNodes.length, 7);
// Should contain the toggle button
var toggleButton = candidatePanelView.element.
querySelector('.keyboard-candidate-panel-toggle-button');
assert.notEqual(toggleButton, null);
candidatePanelView.showMoreCandidates(1, ['9']);
// Check it has the 2nd row
var rows = suggestionsContainer.querySelectorAll('.candidate-row');
assert.equal(rows.length, 2);
// Check 2nd row is shown as a grid
var candidateElements = rows[1].querySelectorAll('span');
assert.equal(candidateElements.length, 2);
assert.equal(candidateElements[0].textContent, '9');
assert.equal(candidateElements[0].dataset.data, '9');
assert.equal(candidateElements[0].style.flexGrow, 1);
// Will have a dummy element here make it look like a grid
assert.equal(candidateElements[1].style.flexGrow, 7);
});
});
suite('candidatePanel with even width for each candidate', function() {
setup(function() {
var options = { widthUnit: 1 };
candidatePanelView = new CandidatePanelView({}, options, viewManager);
});
test('Each candidate has the same width', function() {
candidatePanelView.render();
candidatePanelView.showCandidates(createFakeCandidates(5));
var suggestionsContainer =
candidatePanelView.element.querySelector('.suggestions-container');
assert.notEqual(suggestionsContainer, null);
var candidateElements = suggestionsContainer.
querySelectorAll('.candidate-row span');
assert.equal(candidateElements.length, 5);
for (var i = 0; i < candidateElements.length; i++) {
assert.equal(candidateElements[i].style.flexGrow, 1);
}
});
});
});
});

View file

@ -0,0 +1,60 @@
'use strict';
/* global EmojiKeyView */
require('/js/views/base_view.js');
require('/js/views/emoji_key_view.js');
suite('Views > KeyView', function() {
var emojiKeyView = null;
var viewManager = {
registerView: sinon.stub()
};
suite('some basic functions', function() {
setup(function() {
var target = {};
var options = {};
emojiKeyView = new EmojiKeyView(target, options, viewManager);
});
test(' > render()', function() {
assert.equal(emojiKeyView.element, null);
emojiKeyView.render();
assert.notEqual(emojiKeyView.element, null);
assert.isTrue(emojiKeyView.element.classList.contains('emoji'));
});
test('additional class name', function() {
var key = {
value: 'k',
};
var options = {
classNames: ['another-className']
};
var keyView = new EmojiKeyView(key, options, viewManager);
keyView.render();
options.classNames.forEach(function(className) {
assert.isTrue(keyView.element.classList.contains(className));
});
});
test('invoke viewManager.registerView', function() {
var mockViewManager = {
registerView: this.sinon.stub()
};
var target = {};
var keyView = new EmojiKeyView(target, {}, mockViewManager);
keyView.render();
assert.isTrue(mockViewManager.registerView.calledOnce);
assert.isTrue(mockViewManager.registerView.calledWith(target,
keyView));
});
});
});

View file

@ -0,0 +1,97 @@
'use strict';
/* global HandwritingPadView */
require('/js/views/handwriting_pad_view.js');
suite('Views > HandwritingPadView', function() {
var handwritingPadView;
var canvas;
var STROKE_WIDTH = 6;
var pressStart = {
moved: false,
clientX: 20,
clientY: 20
};
var pressMove = {
moved: true,
clientX: 25,
clientY: 25
};
var rootElement = document.createElement('div');
document.body.appendChild(rootElement);
document.body.style.pad = 0;
document.body.style.margin = 0;
var viewManager = {
registerView: sinon.stub()
};
suite('basic testing', function() {
setup(function() {
var target = {};
handwritingPadView = new HandwritingPadView(target, {}, viewManager);
handwritingPadView.render();
canvas = handwritingPadView.element;
});
test(' > get element', function() {
assert.equal(canvas instanceof HTMLCanvasElement, true);
});
test('invoke viewManager.registerView', function() {
var mockViewManager = {
registerView: this.sinon.stub()
};
var target = {};
var padView = new HandwritingPadView(target, {}, mockViewManager);
padView.render();
assert.isTrue(mockViewManager.registerView.calledOnce);
assert.isTrue(mockViewManager.registerView.calledWith(target,
padView));
});
test(' > drawHandwritingPad()', function() {
rootElement.appendChild(canvas);
var point = handwritingPadView.drawHandwritingPad(pressStart, true,
STROKE_WIDTH);
assert.equal(point.posX, pressStart.clientX * window.devicePixelRatio,
'Error occured in drawCanvas when press start!');
assert.equal(point.posY, pressStart.clientY * window.devicePixelRatio,
'Error occured in drawCanvas when press start!');
point = handwritingPadView.drawHandwritingPad(pressMove, false,
STROKE_WIDTH);
assert.equal(point.posX, pressMove.clientX * window.devicePixelRatio,
'Error occured in drawCanvas when press move!');
assert.equal(point.posY, pressMove.clientY * window.devicePixelRatio,
'Error occured in drawCanvas when press move!');
});
test(' > resize()', function() {
Object.defineProperty(window, 'devicePixelRatio', {
configurable: true,
get: () => 2 }
);
handwritingPadView.resize(200, 400);
var canvas = handwritingPadView.element;
assert.equal(canvas.width, '400');
assert.equal(canvas.height, '800');
assert.equal(canvas.style.width, '200px');
assert.equal(canvas.style.height, '400px');
});
});
});

View file

@ -0,0 +1,244 @@
'use strict';
/* global KeyView */
require('/js/views/key_view.js');
suite('Views > KeyView', function() {
var keyView = null;
var viewManager = {
registerView: sinon.stub()
};
suite('some basic functions', function() {
setup(function() {
var target = {};
var options = {};
keyView = new KeyView(target, options, viewManager);
});
test(' > render()', function() {
assert.equal(keyView.element, null);
keyView.render();
assert.notEqual(keyView.element, null);
});
test(' > highlight() with upper case', function() {
keyView.render();
assert.isFalse(keyView.element.classList.contains('highlighted'));
keyView.highlight({upperCase: true});
assert.isTrue(keyView.element.classList.contains('highlighted'));
assert.isTrue(keyView.element.classList.contains('uppercase-popup'));
});
test(' > highlight() with lower case', function() {
keyView.render();
assert.isFalse(keyView.element.classList.contains('highlighted'));
keyView.highlight({upperCase: false});
assert.isTrue(keyView.element.classList.contains('highlighted'));
assert.isTrue(keyView.element.classList.contains('lowercase-popup'));
});
test(' > unHighlight()', function() {
keyView.render();
keyView.highlight();
assert.isTrue(keyView.element.classList.contains('highlighted'));
keyView.unHighlight();
assert.isFalse(keyView.element.classList.contains('highlighted'));
assert.isFalse(keyView.element.classList.contains('uppercase-popup'));
assert.isFalse(keyView.element.classList.contains('lowercase-popup'));
});
});
suite('DOM structures tests', function() {
test('basic key', function() {
var key = {
value: 'k',
lowercaseValue: 'l_k',
keyCode: 999,
keyCodeUpper: 9999,
targetPage: 2
};
var options = {
keyWidth: 99
};
var keyView = new KeyView(key, options, viewManager);
keyView.render();
assert.isTrue(keyView.element.classList.contains('keyboard-key'));
assert.isFalse(keyView.element.classList.contains('special-key'));
assert.equal(keyView.element.getAttribute('role'), 'key');
assert.equal(keyView.element.style.width, options.keyWidth + 'px');
// Keycode dataset
assert.equal(keyView.element.dataset.keycode, key.keyCode);
assert.equal(keyView.element.dataset.keycodeUpper, key.keyCodeUpper);
// target page dataset
assert.equal(keyView.element.dataset.targetPage, key.targetPage);
//visual wrapper element
var visualWrapper = keyView.element.firstElementChild;
assert.equal(visualWrapper.className, 'visual-wrapper');
// Inner label
var labelNode = visualWrapper.querySelector('.key-element');
assert.equal(labelNode.innerHTML, key.value);
assert.equal(labelNode.dataset.label, key.value);
// popups
var uppercasePopup = visualWrapper.querySelector('.uppercase.popup');
assert.equal(uppercasePopup.innerHTML, key.value);
var lowercasePopup = visualWrapper.querySelector('.lowercase.popup');
assert.equal(lowercasePopup.innerHTML, key.lowercaseValue);
});
test('special key', function() {
var key = {
isSpecialKey: true,
value: 'k',
lowercaseValue: 'l_k'
};
var options = {
keyWidth: 99
};
var keyView = new KeyView(key, options, viewManager);
keyView.render();
assert.isTrue(keyView.element.classList.contains('keyboard-key'));
assert.isTrue(keyView.element.classList.contains('special-key'));
});
test('additional attribute list', function() {
var key = {
value: 'k',
lowercaseValue: 'l_k'
};
var options = {
keyWidth: 99,
attributeList: [
{key: 'testKey', value: 'testValue'},
{key: 'testKey2', value: 'testValue2'}
]
};
var keyView = new KeyView(key, options, viewManager);
keyView.render();
options.attributeList.forEach(function(attribute) {
assert.equal(keyView.element.getAttribute(attribute.key),
attribute.value);
});
});
test('additional class name', function() {
var key = {
value: 'k',
lowercaseValue: 'l_k',
className: 'test-className'
};
var options = {
keyWidth: 99,
classNames: ['another-className']
};
var keyView = new KeyView(key, options, viewManager);
keyView.render();
assert.isTrue(keyView.element.classList.contains('keyboard-key'));
assert.isTrue(keyView.element.classList.contains(key.className));
options.classNames.forEach(function(className) {
assert.isTrue(keyView.element.classList.contains(className));
});
});
test('disabled key', function() {
var key = {
value: 'k',
lowercaseValue: 'l_k',
disabled: true
};
var options = {
keyWidth: 99,
};
var keyView = new KeyView(key, options, viewManager);
keyView.render();
assert.equal(keyView.element.getAttribute('disabled'), 'true');
});
test('alt label node for option w/ altOutputChar case', function() {
var key = {
value: 'k',
lowercaseValue: 'l_k',
};
var options = {
keyWidth: 99,
altOutputChar: '*k'
};
var keyView = new KeyView(key, options, viewManager);
keyView.render();
var visualWrapper = keyView.element.firstElementChild;
// Inner label
var labelNode = visualWrapper.querySelector('.key-element.lowercase');
assert.equal(labelNode.innerHTML, options.altOutputChar);
});
test('altNote', function() {
var key = {
value: 'k',
lowercaseValue: 'l_k',
longPressValue: '#k'
};
var options = {
keyWidth: 99,
altOutputChar: '*k'
};
var keyView = new KeyView(key, options, viewManager);
keyView.render();
var visualWrapper = keyView.element.firstElementChild;
var altNote = visualWrapper.querySelector('.alt-note');
assert.equal(altNote.innerHTML, key.longPressValue);
});
});
suite('Register View to viewManager', function() {
test('invoke viewManager.registerView', function() {
var mockViewManager = {
registerView: this.sinon.stub()
};
var target = {};
var keyView = new KeyView(target, {}, mockViewManager);
keyView.render();
assert.isTrue(mockViewManager.registerView.calledOnce);
assert.isTrue(mockViewManager.registerView.calledWith(target,
keyView));
});
});
});

View file

@ -0,0 +1,144 @@
'use strict';
/* global LatinCandidatePanelView, ViewUtils */
require('/js/views/base_view.js');
require('/js/views/view_utils.js');
require('/js/views/candidate_panel_view.js');
require('/js/views/latin_candidate_panel_view.js');
function createFakeCandidates(count) {
var candidates = [];
for (var i = 0; i < count; i++) {
candidates.push('' + i);
}
return candidates;
}
suite('Views > LatinCandidatePanelView', function() {
var candidatePanelView = null;
var viewManager = {
registerView: sinon.stub()
};
suite('some basic functions', function() {
setup(function() {
var target = {};
var options = {className: 'test-class'};
candidatePanelView =
new LatinCandidatePanelView(target, options, viewManager);
});
test('> render() ', function() {
assert.equal(candidatePanelView.element, null);
candidatePanelView.render();
assert.notEqual(candidatePanelView.element, null);
var classList = candidatePanelView.element.classList;
assert.isTrue(classList.contains('test-class'),
'should contain the className specified in options');
});
test('> show no candidates', function() {
candidatePanelView.render();
candidatePanelView.showCandidates([]);
var suggestionsContainer =
candidatePanelView.element.querySelector('.suggestions-container');
assert.notEqual(suggestionsContainer, null);
// Should show dismiss button
var dismissButton =
candidatePanelView.element.querySelector('.dismiss-suggestions-button');
assert.notEqual(dismissButton, null);
assert.isTrue(dismissButton.classList.contains('hide'));
});
test('> show 3 candidates', function() {
candidatePanelView.render();
candidatePanelView.showCandidates(createFakeCandidates(3));
var suggestionsContainer =
candidatePanelView.element.querySelector('.suggestions-container');
assert.notEqual(suggestionsContainer, null);
var candidateElements = suggestionsContainer.querySelectorAll('span');
assert.equal(candidateElements.length, 3);
for (var i = 0; i < candidateElements.length; i++) {
assert.equal(candidateElements[i].textContent, i);
assert.equal(candidateElements[i].dataset.data, i);
}
// Should show dismiss button
var dismissButton =
candidatePanelView.element.querySelector('.dismiss-suggestions-button');
assert.notEqual(dismissButton, null);
assert.isFalse(dismissButton.classList.contains('hide'));
});
test('> show 3 candidates, with the first as auto correction', function() {
candidatePanelView.render();
candidatePanelView.showCandidates(['*1', '2', '3']);
var suggestionsContainer =
candidatePanelView.element.querySelector('.suggestions-container');
assert.notEqual(suggestionsContainer, null);
var candidateElements = suggestionsContainer.querySelectorAll('div');
assert.equal(candidateElements.length, 3);
// The first candidate should be highlighted
assert.isTrue(candidateElements[0].classList.contains('autocorrect'));
});
test('Candidates scaling to 0.6', function() {
candidatePanelView.render();
sinon.stub(ViewUtils, 'getScale', function() {
return 0.6;
});
var can = ['thisisverylongword', 'alsoverylongword', 'whatup'];
candidatePanelView.showCandidates(can);
var spans = candidatePanelView.element.querySelectorAll('span');
assert.equal(spans[0].textContent, can[0]);
assert.equal(spans[1].textContent, can[1]);
assert.equal(spans[2].textContent, can[2]);
assert.equal(spans[0].style.width, '166.667%');
assert.equal(spans[0].style.transformOrigin, 'left center 0px');
assert.equal(spans[0].style.transform, 'scale(0.6)');
ViewUtils.getScale.restore();
});
test('Candidats scaling to 0.5', function() {
candidatePanelView.render();
sinon.stub(ViewUtils, 'getScale', function() {
return 0.5;
});
var can = ['thisisverylongword', 'alsoverylongword', 'whatup'];
candidatePanelView.showCandidates(can);
var spans = candidatePanelView.element.querySelectorAll('span');
assert.equal(spans[0].textContent, 't…d');
assert.equal(spans[1].textContent, 'a…d');
assert.equal(spans[2].textContent, 'w…p');
assert.equal(spans[0].style.width, '200%');
assert.equal(spans[0].style.transformOrigin, 'left center 0px');
assert.equal(spans[0].style.transform, 'scale(0.5)');
ViewUtils.getScale.restore();
});
});
});

View file

@ -0,0 +1,523 @@
'use strict';
/* global LayoutPageView, KeyboardEvent */
require('/js/views/key_view.js');
require('/js/views/handwriting_pad_view.js');
require('/js/views/layout_page_view.js');
suite('Views > LayoutPageView', function() {
var dummyLayout = {
width: 2,
keys: [
[{ value: 'a' }, { value: 'b' }]
]
};
var viewManager = {
registerView: sinon.stub()
};
test(' > show() ', function() {
var pageView = new LayoutPageView(dummyLayout, {}, viewManager);
pageView.render();
pageView.show();
var container = pageView.element;
assert.equal(container.dataset.active, 'true');
});
test(' > hide() ', function() {
var pageView = new LayoutPageView(dummyLayout, {}, viewManager);
pageView.render();
pageView.hide();
var container = pageView.element;
assert.equal(container.dataset.active, null);
});
test(' > destroy() ', function() {
var pageView = new LayoutPageView(dummyLayout, {}, viewManager);
pageView.render();
pageView.destroy();
var container = pageView.element;
assert.equal(container.parentNode, null);
});
suite(' > render()', function() {
test('Should add last-row class to last row', function() {
var layout = {
width: 2,
keys: [
[{ value: 'a' }, { value: 'b' }],
[{ value: 'c' }, { value: 'd' }],
[{ value: 'e' }, { value: 'f' }]
]
};
var pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
var container = pageView.element;
var rows = container.querySelectorAll('.keyboard-row');
assert.equal(rows.length, 3);
assert.equal(rows[2].classList.contains('keyboard-last-row'), true);
var keys = container.querySelectorAll('.keyboard-key');
assert.equal(keys.length, 6);
});
test('layout.keyClassName should be added to all keys', function() {
var layout = {
width: 2,
keys: [
[{ value: 'a' }, { value: 'b' }]
],
keyClassName: 'c9'
};
var pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
var container = pageView.element;
assert.equal(container.querySelectorAll('.keyboard-key').length, 2);
assert.equal(container.querySelectorAll('.keyboard-key.c9').length, 2);
});
test('Keycode should be set', function() {
var layout = {
width: 9,
keys: [
[{ value: 'a', keyCode: 3 }, { value: 'b', keyCode: 98 }]
]
};
var pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
var container = pageView.element;
var keys = container.querySelectorAll('.keyboard-key');
assert.equal(keys[0].dataset.keycode, 3);
assert.equal(keys[1].dataset.keycode, 98);
});
test('On uppercase flag, uppercase on keys, ' +
'no lowercase class on container', function() {
var layout = {
width: 2,
keys: [
[{ value: 'a', uppercaseValue: 'A' },
{ value: 'b', uppercaseValue: 'B' }]
]
};
var pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
pageView.setUpperCaseLock({
isUpperCase: true,
isUpperCaseLocked: false
});
var container = pageView.element;
var keys = container.querySelectorAll('.keyboard-key .key-element');
assert.equal(keys.length, 4);
assert.equal(keys[0].textContent, 'A');
assert.isTrue(keys[1].classList.contains('lowercase'));
assert.equal(keys[1].textContent, 'a');
assert.equal(keys[2].textContent, 'B');
assert.isTrue(keys[3].classList.contains('lowercase'));
assert.equal(keys[3].textContent, 'b');
assert.isFalse(container.classList.contains('lowercase'));
});
test('No uppercase flag, uppercase on keys, ' +
'lowercase class on container', function() {
var layout = {
width: 2,
keys: [
[{ value: 'a', uppercaseValue: 'A' },
{ value: 'b', uppercaseValue: 'B' }]
]
};
var pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
pageView.setUpperCaseLock({
isUpperCase: false,
isUpperCaseLocked: false
});
var container = pageView.element;
var keys = container.querySelectorAll('.keyboard-key .key-element');
assert.equal(keys.length, 4);
assert.equal(keys[0].textContent, 'A');
assert.isTrue(keys[1].classList.contains('lowercase'));
assert.equal(keys[1].textContent, 'a');
assert.equal(keys[2].textContent, 'B');
assert.isTrue(keys[3].classList.contains('lowercase'));
assert.equal(keys[3].textContent, 'b');
assert.isTrue(container.classList.contains('lowercase'));
});
test('create keyboard with handwriting pad', function() {
var layout = {
handwritingPadOptions: {
ratio: 8.5,
rowspan: 3
},
keys: [
[
{ value: 'a', ratio: 1.5 }
], [
{ value: 'b', ratio: 1.5 }
], [
{ value: 'c', ratio: 1.5 }
], [
{ value: 'd', ratio: 10 }
]
]
};
var pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
var container = pageView.element;
var pads = container.querySelectorAll('.handwriting-pad');
assert.equal(pads.length, 1);
});
suite('CSS classes on pageView', function() {
test('with specificCssRule', function() {
var layout = {
width: 1,
keys: [],
layoutName: 'ar',
specificCssRule: true
};
var pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
var container = pageView.element;
assert.equal(container.classList.contains('ar'), true);
});
test('without specificCssRule', function() {
var layout = {
width: 1,
keys: [],
layoutName: 'ar',
specificCssRule: false
};
var pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
var container = pageView.element;
assert.equal(container.classList.contains('ar'), false);
});
});
});
suite(' > setUpperCaseLock()', function() {
var pageView = null;
setup(function() {
var layout = {
width: 2,
keys: [
[{ value: 'a' },
{ value: 'Shift', keyCode: KeyboardEvent.DOM_VK_CAPS_LOCK }
]
]
};
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
});
test('turn to uppercase', function() {
pageView.setUpperCaseLock({
isUpperCase: true,
isUpperCaseLocked: false
});
var container = pageView.element;
assert.isFalse(container.classList.contains('lowercase'));
var capsLockKey = container.querySelector(
'[data-keycode="' + KeyboardEvent.DOM_VK_CAPS_LOCK + '"]'
);
assert.isTrue(capsLockKey.classList.contains('kbr-key-active'));
assert.isFalse(capsLockKey.classList.contains('kbr-key-hold'));
assert.equal(capsLockKey.getAttribute('aria-pressed'), 'true');
});
test('turn to lowercase', function() {
pageView.setUpperCaseLock({
isUpperCase: false,
isUpperCaseLocked: false
});
var container = pageView.element;
assert.isTrue(container.classList.contains('lowercase'));
var capsLockKey = container.querySelector(
'[data-keycode="' + KeyboardEvent.DOM_VK_CAPS_LOCK + '"]'
);
assert.isFalse(capsLockKey.classList.contains('kbr-key-active'));
assert.isFalse(capsLockKey.classList.contains('kbr-key-hold'));
assert.equal(capsLockKey.getAttribute('aria-pressed'), 'false');
});
test('enable CapsLock', function() {
pageView.setUpperCaseLock({
isUpperCase: true,
isUpperCaseLocked: true
});
var container = pageView.element;
assert.isFalse(container.classList.contains('lowercase'));
var capsLockKey = container.querySelector(
'[data-keycode="' + KeyboardEvent.DOM_VK_CAPS_LOCK + '"]'
);
assert.isFalse(capsLockKey.classList.contains('kbr-key-active'));
assert.isTrue(capsLockKey.classList.contains('kbr-key-hold'));
assert.equal(capsLockKey.getAttribute('aria-pressed'), 'true');
});
});
suite(' > highlightKey() and unHighlightKey()', function() {
var pageView = null;
var keyView;
setup(function() {
var layout = {
width: 2,
keys: []
};
keyView = {
highlight: sinon.stub(),
unHighlight: sinon.stub()
};
var viewManager = {
getView: function() {
return keyView;
}
};
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
});
test('highlightKey() with upperCase', function() {
pageView.isUpperCase = true;
pageView.highlightKey({});
assert.isTrue(keyView.highlight.calledOnce);
assert.isTrue(keyView.highlight.calledWith({upperCase: true}));
});
test('highlightKey() with upperCase', function() {
pageView.isUpperCase = false;
pageView.highlightKey({});
assert.isTrue(keyView.highlight.calledOnce);
assert.isTrue(keyView.highlight.calledWith({upperCase: false}));
});
test('unHighlightKey()', function() {
pageView.unHighlightKey({});
assert.isTrue(keyView.unHighlight.calledOnce);
});
});
suite('> getHeight()', function() {
var layout;
var pageView = null;
var viewManager = {
registerView: sinon.stub(),
getRemToPx: sinon.stub(),
screenInPortraitMode: sinon.stub()
};
var rootElement;
setup(function() {
rootElement = document.createElement('div');
document.body.appendChild(rootElement);
layout = {
width: 2,
keys: [
[{ value: 'a' }, { value: 'b' }],
[{ value: 'c' }, { value: 'd' }],
[{ value: 'e' }, { value: 'f' }],
[{ value: 'g' }, { value: 'h' }]
]
};
});
teardown(function() {
document.body.removeChild(rootElement);
});
test('w/ 4 rows, portrait', function() {
viewManager.getRemToPx.returns(10);
viewManager.screenInPortraitMode.returns(true);
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
assert.equal(pageView.getHeight(), 4 * ((4.5 + 0.8) * 10));
});
test('w/ 4 rows, landscape', function() {
viewManager.getRemToPx.returns(10);
viewManager.screenInPortraitMode.returns(false);
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
assert.equal(pageView.getHeight(), 4 * ((3.8 + 0.8) * 10));
});
test('w/ 5 rows, portrait', function() {
layout.keys.push([{ value: 'i' }, { value: 'j' }]);
viewManager.getRemToPx.returns(10);
viewManager.screenInPortraitMode.returns(true);
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
assert.equal(pageView.getHeight(), 5 * ((3.4 + 0.8) * 10));
});
test('w/ 5 rows, landscape', function() {
layout.keys.push([{ value: 'i' }, { value: 'j' }]);
viewManager.getRemToPx.returns(10);
viewManager.screenInPortraitMode.returns(false);
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
assert.equal(pageView.getHeight(), 5 * ((2.85 + 0.8) * 10));
});
});
suite(' > getVisualData()', function() {
var layout = {
width: 2,
keys: [
[{ value: 'a' }, { value: 'b' }],
[{ value: 'c' }, { value: 'd' }],
[{ value: 'e' }, { value: 'f' }]
]
};
var pageView = null;
var viewManager = {
registerView: sinon.stub()
};
var rootElement;
setup(function() {
rootElement = document.createElement('div');
document.body.appendChild(rootElement);
});
teardown(function() {
document.body.removeChild(rootElement);
});
test('check getVisualData sanity', function() {
var layout = {
width: 10,
keys: [
[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
]
};
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
rootElement.appendChild(pageView.element);
var vData = pageView.getVisualData();
var visuals = [].slice.call(
document.querySelectorAll('.visual-wrapper'));
visuals.forEach(function(v, ix) {
assert.equal(v.offsetLeft, vData[ix].x, 'x for ' + ix);
assert.equal(v.offsetTop, vData[ix].y, 'y for ' + ix);
assert.equal(v.clientWidth, vData[ix].width, 'width for ' + ix);
assert.equal(v.clientHeight, vData[ix].height, 'height for ' + ix);
});
});
test('check getVisualData sanity for filled up space', function() {
var layout = {
width: 4,
keys: [
[{}, {}, {}]
]
};
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
rootElement.appendChild(pageView.element);
var vData = pageView.getVisualData();
var visuals = [].slice.call(
document.querySelectorAll('.visual-wrapper'));
visuals.forEach(function(v, ix) {
assert.equal(v.offsetLeft, vData[ix].x, 'x for ' + ix);
assert.equal(v.offsetTop, vData[ix].y, 'y for ' + ix);
assert.equal(v.clientWidth, vData[ix].width, 'width for ' + ix);
assert.equal(v.clientHeight, vData[ix].height, 'height for ' + ix);
});
});
test('getVisualData will return cached data', function() {
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
var vData = pageView.getVisualData();
var vData2 = pageView.getVisualData();
assert.equal(vData, vData2);
});
test('getVisualData() will return cached data for different ' +
'size', function() {
pageView = new LayoutPageView(layout, {}, viewManager);
pageView.render();
var vData = pageView.getVisualData();
pageView.resize(480);
var vData2 = pageView.getVisualData();
assert.notEqual(vData, vData2);
var vData3 = pageView.getVisualData();
assert.equal(vData2, vData3);
});
});
});

View file

@ -0,0 +1,84 @@
'use strict';
/* global SwipeablePageView */
require('/js/views/key_view.js');
require('/js/views/layout_page_view.js');
require('/js/views/swipeable_section_view.js');
require('/js/views/swiping_detector.js');
require('/js/views/swipeable_panel_view.js');
require('/js/views/swipeable_page_view.js');
suite('Views > SwipeablePageView', function() {
var pageView = null;
var viewManager = {
registerView: sinon.stub()
};
setup(function() {
var dummyLayout = {
width: 2,
panelKeys: [
[{ value: 'a' }, { value: 'b' }]
],
keys: [
[{ value: 'a' }, { value: 'b' }]
]
};
pageView = new SwipeablePageView(dummyLayout, {},
viewManager);
});
suite('some basic functions', function() {
test('> render() ', function() {
assert.equal(pageView.element, null);
pageView.render();
assert.notEqual(pageView.element, null);
pageView.show();
assert.equal(pageView.element.dataset.active, 'true');
assert.ok(pageView.element.classList.contains('uppercase-only'));
var rows = pageView.element.querySelectorAll('.keyboard-row');
assert.equal(rows.length, 1);
assert.ok(rows[0].classList.contains('swipe-switching-buttons'));
});
});
suite('CSS classes on pageView', function() {
test('with specificCssRule', function() {
var layout = {
panelKeys: [],
keys: [],
layoutName: 'ar',
specificCssRule: true
};
var pageView = new SwipeablePageView(layout, {}, viewManager);
pageView.render();
var container = pageView.element;
assert.equal(container.classList.contains('ar'), true);
});
test('without specificCssRule', function() {
var layout = {
width: 1,
panelKeys: [],
keys: [],
layoutName: 'ar',
specificCssRule: false
};
var pageView = new SwipeablePageView(layout, {}, viewManager);
pageView.render();
var container = pageView.element;
assert.equal(container.classList.contains('ar'), false);
});
});
});

View file

@ -0,0 +1,395 @@
'use strict';
/* global SwipeablePanelView */
require('/js/views/base_view.js');
require('/js/views/key_view.js');
require('/js/views/emoji_key_view.js');
require('/js/views/swiping_detector.js');
require('/js/views/swipeable_panel_view.js');
suite('Views > SwipeablePanelView', function() {
var panelView = null;
var viewManager = {
registerView: sinon.stub()
};
var layout = {
panelKeys: []
};
var sectionCount = 4;
for (var i = 0; i < 18 * sectionCount; i++) {
layout.panelKeys.push({ value: i, type: 'emoji' });
}
setup(function() {
var options = {
};
panelView = new SwipeablePanelView(layout, options,
viewManager);
});
suite('some basic functions', function() {
test('> render() ', function() {
assert.equal(panelView.element, null);
panelView.render();
assert.notEqual(panelView.element, null);
});
test('> render() check indicator elements', function() {
panelView.render();
var indicators = panelView.element.querySelectorAll('.section-indicator');
assert.equal(indicators.length, sectionCount);
assert.ok(indicators[0].classList.contains('active'));
});
test('> move to the next section', function() {
panelView.render();
panelView.gotoSection(1);
var indicators = panelView.element.querySelectorAll('.section-indicator');
assert.isFalse(indicators[0].classList.contains('active'));
assert.ok(indicators[1].classList.contains('active'));
});
});
suite('utilize different KeyView type', function() {
test('> render() with KeyView ', function() {
var layout = {
panelKeys: [{value: 'key1'}, {value: 'key2'}]
};
var panelView = new SwipeablePanelView(layout, {}, viewManager);
panelView.render();
var keyView = panelView.element.querySelector('button.keyboard-key');
assert.notEqual(keyView, null);
});
test('> render() with EmojiKeyView ', function() {
var layout = {
panelKeys: [{value: 'key1', type: 'emoji'},
{value: 'key2', type: 'emoji'}]
};
var panelView = new SwipeablePanelView(layout, {}, viewManager);
panelView.render();
var keyView = panelView.element.querySelector('button.emoji');
assert.notEqual(keyView, null);
});
});
suite('Render different number of elements', function() {
test('> render() with no elements', function() {
var layout = {
panelKeys: [{value: 'key1'}, {value: 'key2'}]
};
panelView = new SwipeablePanelView(layout, {}, viewManager);
panelView.render();
assert.equal(panelView.sections[1], null);
});
test('> render() with 2 emoji elements', function() {
var layout = {
panelKeys: [{value: 'key1', type: 'emoji'},
{value: 'key2', type: 'emoji'}]
};
panelView = new SwipeablePanelView(layout, {}, viewManager);
panelView.render();
var section = panelView.sections[0];
var keys = section.querySelectorAll('button.emoji');
assert.equal(keys.length, 2);
var dummyElement = section.querySelector('span');
assert.equal(dummyElement.style.flexGrow, 4);
});
test('> render() one section at a time', function() {
var layout = {
panelKeys: []
};
for (var i = 0; i < 20; i++) {
layout.panelKeys.push({value: 'key' + i, type: 'emoji'});
}
panelView = new SwipeablePanelView(layout, {}, viewManager);
panelView.render();
var keys = panelView.sections[0].querySelectorAll('button.emoji');
assert.equal(keys.length, 18);
keys = panelView.sections[1].querySelectorAll('button.emoji');
assert.equal(keys.length, 2);
assert.equal(keys[0].textContent, 'key18');
});
});
suite('panning', function() {
var rootElement = document.createElement('div');
setup(function() {
document.body.appendChild(rootElement);
var options = {
totalWidth: 320
};
panelView = new SwipeablePanelView(layout, options,
viewManager);
panelView.render();
});
teardown(function() {
rootElement.innerHTML = '';
});
test('> panning the first section - forward', function() {
assert.equal(panelView.sections[0].style.transform, '');
panelView._handleTouchStart({
position: {clientX: 20, clientY: 0}
});
panelView._handlePan({
dx: -20,
position: {clientX: 0, clientY: 0}
});
assert.equal(panelView.sections[0].style.transform, 'translateX(-20px)');
assert.equal(panelView.sections[1].style.transform, 'translateX(300px)');
});
test('> panning the first section - backward', function() {
assert.equal(panelView.sections[0].style.transform, '');
panelView._handleTouchStart({
position: {clientX: 0, clientY: 0}
});
panelView._handlePan({
dx: 20,
position: {clientX: 20, clientY: 0}
});
assert.equal(panelView.sections[0].style.transform, '');
});
test('> panning the second section - forward', function() {
panelView.gotoSection(1);
panelView._handleTouchStart({
position: {clientX: 20, clientY: 0}
});
panelView._handlePan({
dx: -20,
position: {clientX: 0, clientY: 0}
});
assert.equal(panelView.sections[1].style.transform, 'translateX(-20px)');
assert.equal(panelView.sections[2].style.transform, 'translateX(300px)');
});
test('> panning the second section - backward', function() {
panelView.gotoSection(1);
panelView._handleTouchStart({
position: {clientX: 20, clientY: 0}
});
panelView._handlePan({
dx: 20,
position: {clientX: 40, clientY: 0}
});
assert.equal(panelView.sections[0].style.transform, 'translateX(-300px)');
assert.equal(panelView.sections[1].style.transform, 'translateX(20px)');
});
test('> panning the last section - forward', function() {
panelView.gotoSection(sectionCount - 1);
panelView._handleTouchStart({
position: {clientX: 20, clientY: 0}
});
panelView._handlePan({
dx: -20,
position: {clientX: 0, clientY: 0}
});
assert.equal(panelView.sections[sectionCount - 1].style.transform,
'translateX(0px)');
});
test('> panning the last section - backward', function() {
panelView.gotoSection(sectionCount - 1);
panelView._handleTouchStart({
position: {clientX: 20, clientY: 0}
});
panelView._handlePan({
dx: 20,
position: {clientX: 40, clientY: 0}
});
assert.equal(panelView.sections[sectionCount - 1].style.transform,
'translateX(20px)');
assert.equal(panelView.sections[sectionCount - 2].style.transform,
'translateX(-300px)');
});
test('> swiping through the first section - short distance', function() {
rootElement.appendChild(panelView.element);
panelView._handleTouchStart({
position: {clientX: 20, clientY: 0}
});
panelView._handlePan({
dx: -20,
position: {clientX: 0, clientY: 0}
});
assert.equal(panelView.sections[0].style.transform, 'translateX(-20px)');
panelView._handleSwipe({
direction: 'left',
vx: 0.3
});
assert.equal(panelView.sections[0].style.transform, 'translateX(0px)');
});
test('> swiping through the first section - far enough', function() {
rootElement.appendChild(panelView.element);
panelView._handleTouchStart({
position: {clientX: 100, clientY: 0}
});
panelView._handlePan({
dx: -100,
position: {clientX: 0, clientY: 0}
});
assert.equal(panelView.sections[0].style.transform, 'translateX(-100px)');
panelView._handleSwipe({
direction: 'left',
vx: -0.3
});
assert.equal(panelView.sections[0].style.transform, 'translateX(-320px)');
assert.equal(panelView.sections[1].style.transform, 'translateX(0px)');
});
test('> swiping through the first section - fast enough', function() {
rootElement.appendChild(panelView.element);
panelView._handleTouchStart({
position: {clientX: 20, clientY: 0}
});
panelView._handlePan({
dx: -20,
position: {clientX: 0, clientY: 0}
});
assert.equal(panelView.sections[0].style.transform, 'translateX(-20px)');
panelView._handleSwipe({
direction: 'left',
vx: -1
});
assert.equal(panelView.sections[0].style.transform, 'translateX(-320px)');
assert.equal(panelView.sections[1].style.transform, 'translateX(0px)');
});
test('> swiping back to the first section, > threshold', function() {
rootElement.appendChild(panelView.element);
panelView.gotoSection(1);
panelView._handleTouchStart({
position: {clientX: 20, clientY: 0}
});
panelView._handlePan({
dx: 100,
position: {clientX: 120, clientY: 0}
});
assert.equal(panelView.sections[1].style.transform, 'translateX(100px)');
panelView._handleSwipe({
direction: 'right',
vx: 0.3
});
assert.equal(panelView.sections[0].style.transform, 'translateX(0px)');
assert.equal(panelView.sections[1].style.transform, 'translateX(320px)');
});
});
suite('rotate', function() {
var rootElement = document.createElement('div');
setup(function() {
document.body.appendChild(rootElement);
var options = { totalWidth: 320 };
panelView = new SwipeablePanelView(layout, options,
viewManager);
panelView.render();
});
teardown(function() {
rootElement.innerHTML = '';
});
test('> rotate to landscape - at first section', function() {
panelView.resize(590);
assert.equal(panelView.sections[0].style.transform, 'translateX(0px)');
assert.equal(panelView.sections[1].style.transform, 'translateX(590px)');
});
test('> rotate to landscape - at second section', function() {
panelView.gotoSection(1);
panelView.resize(590);
assert.equal(panelView.sections[0].style.transform, 'translateX(-590px)');
assert.equal(panelView.sections[1].style.transform, 'translateX(0px)');
assert.equal(panelView.sections[2].style.transform, 'translateX(590px)');
});
test('> rotate to landscape - at last section', function() {
panelView.gotoSection(sectionCount - 1);
panelView.resize(590);
assert.equal(
panelView.sections[sectionCount - 1].style.transform,
'translateX(0px)');
assert.equal(
panelView.sections[sectionCount - 2].style.transform,
'translateX(-590px)');
});
});
});

View file

@ -0,0 +1,161 @@
'use strict';
/* global SwipingDetector */
require('/js/views/swiping_detector.js');
suite('View utils > SwipingDetector', function() {
function fakeTouchDispatch(type, panel, xs, ys) {
var touches = [];
for (var i = 0; i < xs.length; i++) {
var x = xs[i];
var y = ys[i];
var touch = document.createTouch(window, panel, 42, x, y,
x, y, x, y,
0, 0, 0, 0);
touches.push(touch);
}
var touchList = document.createTouchList(touches);
var eventTouches = (type == 'touchstart' || type == 'touchmove') ?
touchList : null;
var eventChanged = (type == 'touchmove') ?
null : touchList;
var e = document.createEvent('TouchEvent');
e.initTouchEvent(type, true, true,
null, null, false, false, false, false,
eventTouches, null, eventChanged);
panel.dispatchEvent(e);
return e;
}
function touchStart(panel, xs, ys) {
return fakeTouchDispatch('touchstart', panel, xs, ys);
}
function touchMove(panel, xs, ys) {
return fakeTouchDispatch('touchmove', panel, xs, ys);
}
function touchEnd(panel, xs, ys) {
return fakeTouchDispatch('touchend', panel, xs, ys);
}
function swipe(clock, panel, fromX, toX, fromY, toY, duration, noEnd) {
var events = [];
duration = duration || 350;
events.push(touchStart(panel, [fromX], [fromY]));
var diffX = Math.abs(toX - fromX);
var diffY = Math.abs(toY - fromY);
var delta = Math.max(diffX, diffY);
var step = step || 1;
var x = 0, y = 0;
var tick = duration / delta;
for (var i = 0; i < delta; i++) {
var newX = fromX + x;
var newY = fromY + y;
events.push(touchMove(panel, [newX], [newY]));
clock.tick(tick);
if (newX < toX) {
x++;
}
if (newX > toX) {
x--;
}
if (newY < toY) {
y++;
}
if (newY > toY) {
y--;
}
}
if (!noEnd) {
events.push(touchEnd(panel, [toX], [toY]));
}
return events;
}
function createFakeCoordinates(x, y, timeStamp, id) {
return Object.freeze({
screenX: x,
screenY: y,
clientX: x,
clientY: y,
timeStamp: timeStamp,
identifier: id
});
}
var swipingDetector = null;
var element = null;
setup(function() {
element = document.createElement('div');
swipingDetector = new SwipingDetector(element);
this.sinon.useFakeTimers();
});
test('init', function() {
swipingDetector.start();
});
test('pan', function() {
swipingDetector.start();
var panHandler = this.sinon.stub();
swipingDetector.onpan = panHandler;
swipe(this.sinon.clock, element, 21, 0, 0, 0, 100, true);
assert.equal(panHandler.lastCall.args[0].dx, -20);
});
test('swipe', function() {
swipingDetector.start();
var swipeHandler = this.sinon.stub();
swipingDetector.onswipe = swipeHandler;
swipe(this.sinon.clock, element, 0, 21, 0, 0, 100);
assert.equal(swipeHandler.firstCall.args[0].direction, 'right');
swipe(this.sinon.clock, element, 20, 0, 0, 0, 300);
assert.equal(swipeHandler.lastCall.args[0].direction, 'left');
});
test('swipe will report velocity', function() {
swipingDetector.start();
var swipeHandler = this.sinon.stub();
swipingDetector.onswipe = swipeHandler;
swipingDetector.handleEvent({
type: 'touchstart',
touches: [createFakeCoordinates(0, 0, 0)],
timeStamp: 0
});
swipingDetector.handleEvent({
type: 'touchmove',
touches: [createFakeCoordinates(20, 0, 0)],
timeStamp: 100
});
swipingDetector.handleEvent({
type: 'touchend',
changedTouches: [createFakeCoordinates(20, 0, 0)],
timeStamp: 100
});
assert.equal(swipeHandler.firstCall.args[0].vx, 0.2);
});
});