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,85 @@
'use strict';
/* global MockIntlHelper */
suite('Picker', function() {
var Picker, Spinner;
suiteSetup(function(done) {
window.IntlHelper = MockIntlHelper;
window.IntlHelper.define('digit-nopadding', 'number', {
style: 'decimal',
useGrouping: false
});
require(['picker/picker', 'picker/spinner'],
function(picker, spinner) {
Picker = picker;
Spinner = spinner;
done();
});
});
test('shape:prototype ', function() {
assert.ok(Picker);
assert.typeOf(Picker.prototype.reset, 'function');
assert.typeOf(Picker.prototype.value, 'null');
assert.isNull(Picker.prototype.value);
});
var picker;
setup(function() {
var pickerEl = document.createElement('div');
pickerEl.appendChild(document.createElement('div'))
.classList.add('picker-hours');
pickerEl.appendChild(document.createElement('div'))
.classList.add('picker-minutes');
picker = new Picker({
element: pickerEl,
pickers: {
hours: {
range: [0, 23]
},
minutes: {
range: [0, 59],
isPadded: true
}
}
});
});
test('shape:instance ', function() {
assert.typeOf(picker.nodes, 'object');
assert.typeOf(picker.spinners, 'object');
assert.typeOf(picker.pickers, 'Array');
assert.notEqual(typeof picker.nodes.hours, 'undefined');
assert.notEqual(typeof picker.nodes.minutes, 'undefined');
assert.notEqual(typeof picker.spinners.hours, 'undefined');
assert.notEqual(typeof picker.spinners.hours, 'undefined');
assert.deepEqual(picker.pickers, ['hours', 'minutes']);
});
test('values ', function() {
var spinners = picker.spinners;
assert.equal(spinners.hours.values[0], 0);
assert.equal(spinners.hours.values[23], 23);
assert.equal(spinners.hours.values[24], undefined);
assert.equal(spinners.minutes.values[0], 0);
assert.equal(spinners.minutes.values[59], 59);
assert.equal(spinners.minutes.values[60], undefined);
assert.equal(picker.value, '0:0');
});
test('get and set value ', function() {
picker.value = '1:59';
var spinners = picker.spinners;
assert.equal(spinners.hours.value, 1);
assert.equal(spinners.minutes.value, 59);
});
});

View file

@ -0,0 +1,396 @@
suite('Spinner', function() {
'use strict';
/* global MockIntlHelper, IntlHelper */
var Spinner, GestureDetector;
var _clientHeight;
var VALUE_ELEMENT_HEIGHT = 20;
suiteSetup(function(done) {
window.IntlHelper = MockIntlHelper;
IntlHelper.define('digit-nopadding', 'number', {
style: 'decimal',
useGrouping: false
});
// override native clientHeight
_clientHeight = Object.getOwnPropertyDescriptor(
Element.prototype, 'clientHeight');
Object.defineProperty(Element.prototype, 'clientHeight', {
configurable: true,
enumerable: true,
get: function clockTestClientHeightStub() {
if (this.classList.contains('picker-unit')) {
return VALUE_ELEMENT_HEIGHT;
}
return _clientHeight.get.call(this);
}
});
require([
'picker/spinner',
'shared/js/gesture_detector'
], function(spinner, GD) {
Spinner = spinner;
GestureDetector = GD;
done();
});
});
suiteTeardown(function() {
Object.defineProperty(Element.prototype, 'clientHeight', _clientHeight);
});
setup(function() {
VALUE_ELEMENT_HEIGHT = 20;
this.container = document.createElement('div');
this.container.classList.add('test-spinner-container');
this.element = document.createElement('div');
this.element.classList.add('test-spinner-element');
this.container.appendChild(this.element);
document.body.appendChild(this.container);
this.clock = this.sinon.useFakeTimers();
});
function checkTranslate(value) {
test('Checking translate is ' + value, function() {
assert.equal(this.element.style.transform,
'translateY(' + value + 'px)');
assert.equal(this.spinner.top, value);
});
}
function checkIndex(index) {
test('Checking index is ' + index, function() {
assert.equal(this.spinner.index, index);
assert.equal(this.spinner.value, this.spinner.values[index]);
});
}
function checkCreation() {
checkTranslate(0);
checkIndex(0);
}
suite('values: [0, 1, 2]', function() {
setup(function() {
this.spinner = new Spinner({
element: this.element,
values: [0, 1, 2]
});
});
checkCreation();
suite('select option 2', function() {
setup(function() {
this.spinner.select(2);
});
checkTranslate(-40);
checkIndex(2);
});
suite('select option 3 (out of range)', function() {
setup(function() {
this.spinner.select(3);
});
checkTranslate(-40);
checkIndex(2);
});
suite('set value 2', function() {
setup(function() {
this.spinner.value = 2;
});
checkTranslate(-40);
checkIndex(2);
});
suite('set value out of range', function() {
setup(function() {
this.spinner.value = 'nope';
});
checkTranslate(0);
checkIndex(0);
});
suite('touchstart', function() {
setup(function() {
this.event = new CustomEvent('touchstart', {
cancelable: true,
bubbles: true
});
this.event.changedTouches = [];
this.element.dispatchEvent(this.event);
});
test('default is prevented', function() {
assert.ok(this.event.defaultPrevented);
});
});
suite('pan down by 15px over 1 second', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 15,
timeStamp: 1000
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
// top should still be at zero, can't go "down" in the spinner
checkTranslate(0);
});
suite('pan up by 15px over 1 second', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 15,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 1000
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-15);
checkIndex(1);
suite('pan finished w/ low (therefore zero) momentum', function() {
setup(function() {
var event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-20);
checkIndex(1);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
});
});
suite('values: [0...30]', function() {
setup(function() {
this.spinner = new Spinner({
element: this.element,
values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
});
});
checkCreation();
suite('pan up by 35px over 70ms', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 35,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 70
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-35);
checkIndex(2);
suite('pan finished w/ momentum', function() {
setup(function() {
var event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-200);
checkIndex(10);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
suite('pan times out', function() {
setup(function() {
this.clock.tick(201);
});
checkTranslate(-40);
checkIndex(2);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
});
suite('pan up by 100px over 1ms', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 100,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 1
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-100);
checkIndex(5);
suite('pan finished w/ insane momentum', function() {
setup(function() {
var event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-400);
checkIndex(20);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
suite('start pan', function() {
setup(function() {
var event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
test('animation-on removed', function() {
assert.isFalse(
this.element.classList.contains('animation-on'));
});
suite('finish pan down 20px over 100ms', function() {
// this is a smaller scale pan, moving one unit per 100ms
setup(function() {
var event = new CustomEvent('pan', {
detail: {
position: {
clientY: 20,
timeStamp: 100
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
// total difference = 4, 1 moved + 3 inertia
checkTranslate(-320);
checkIndex(16);
});
});
});
suite('pan times out', function() {
setup(function() {
this.clock.tick(201);
});
checkTranslate(-100);
checkIndex(5);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
});
});
suite('values: [0...30] - big elements', function() {
// results should have same index, as previous test,
// but double the px values for translates and motion because of bigger
// elements
setup(function() {
VALUE_ELEMENT_HEIGHT = 40;
this.spinner = new Spinner({
element: this.element,
values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
});
});
checkCreation();
suite('pan up by 70px over 70ms', function() {
setup(function() {
var event;
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 70,
timeStamp: 0
}
},
bubbles: true
});
this.container.dispatchEvent(event);
event = new CustomEvent('pan', {
detail: {
position: {
clientY: 0,
timeStamp: 70
}
},
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-70);
checkIndex(2);
suite('pan finished w/ momentum', function() {
setup(function() {
var event = new CustomEvent('swipe', {
bubbles: true
});
this.container.dispatchEvent(event);
});
checkTranslate(-400);
checkIndex(10);
test('animation-on', function() {
assert.ok(this.element.classList.contains('animation-on'));
});
});
});
});
});