mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 05:21:52 +08:00
This reverts commit 9273f97a0cfbb007f20d4977bde3933d6933f9e5.
This commit is contained in:
@ -261,36 +261,11 @@ export class Datetime implements ComponentInterface {
|
|||||||
|
|
||||||
const pickerOptions = this.generatePickerOptions();
|
const pickerOptions = this.generatePickerOptions();
|
||||||
const picker = await this.pickerCtrl.create(pickerOptions);
|
const picker = await this.pickerCtrl.create(pickerOptions);
|
||||||
|
|
||||||
this.isExpanded = true;
|
this.isExpanded = true;
|
||||||
picker.onDidDismiss().then(() => {
|
picker.onDidDismiss().then(() => {
|
||||||
this.isExpanded = false;
|
this.isExpanded = false;
|
||||||
this.setFocus();
|
this.setFocus();
|
||||||
});
|
});
|
||||||
picker.addEventListener('ionPickerColChange', async (event: any) => {
|
|
||||||
const data = event.detail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't bother checking for non-dates as things like hours or minutes
|
|
||||||
* are always going to have the same number of column options
|
|
||||||
*/
|
|
||||||
if (data.name !== 'month' && data.name !== 'day' && data.name !== 'year') { return; }
|
|
||||||
|
|
||||||
const colSelectedIndex = data.selectedIndex;
|
|
||||||
const colOptions = data.options;
|
|
||||||
|
|
||||||
const changeData: any = {};
|
|
||||||
changeData[data.name] = {
|
|
||||||
value: colOptions[colSelectedIndex].value
|
|
||||||
};
|
|
||||||
|
|
||||||
this.updateDatetimeValue(changeData);
|
|
||||||
const columns = this.generateColumns();
|
|
||||||
|
|
||||||
picker.columns = columns;
|
|
||||||
|
|
||||||
await this.validate(picker);
|
|
||||||
});
|
|
||||||
await this.validate(picker);
|
await this.validate(picker);
|
||||||
await picker.present();
|
await picker.present();
|
||||||
}
|
}
|
||||||
@ -325,7 +300,6 @@ export class Datetime implements ComponentInterface {
|
|||||||
text: this.cancelText,
|
text: this.cancelText,
|
||||||
role: 'cancel',
|
role: 'cancel',
|
||||||
handler: () => {
|
handler: () => {
|
||||||
this.updateDatetimeValue(this.value);
|
|
||||||
this.ionCancel.emit();
|
this.ionCancel.emit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, ComponentInterface, Element, Event, EventEmitter, Prop, QueueApi, Watch } from '@stencil/core';
|
import { Component, ComponentInterface, Element, Prop, QueueApi } from '@stencil/core';
|
||||||
|
|
||||||
import { Gesture, GestureDetail, Mode, PickerColumn } from '../../interface';
|
import { Gesture, GestureDetail, Mode, PickerColumn } from '../../interface';
|
||||||
import { hapticSelectionChanged } from '../../utils/haptic';
|
import { hapticSelectionChanged } from '../../utils/haptic';
|
||||||
@ -36,18 +36,8 @@ export class PickerColumnCmp implements ComponentInterface {
|
|||||||
|
|
||||||
@Prop({ context: 'queue' }) queue!: QueueApi;
|
@Prop({ context: 'queue' }) queue!: QueueApi;
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when the selected value has changed
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
@Event() ionPickerColChange!: EventEmitter<PickerColumn>;
|
|
||||||
|
|
||||||
/** Picker column data */
|
/** Picker column data */
|
||||||
@Prop() col!: PickerColumn;
|
@Prop() col!: PickerColumn;
|
||||||
@Watch('col')
|
|
||||||
protected colChanged() {
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillLoad() {
|
componentWillLoad() {
|
||||||
let pickerRotateFactor = 0;
|
let pickerRotateFactor = 0;
|
||||||
@ -98,10 +88,6 @@ export class PickerColumnCmp implements ComponentInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private emitColChange() {
|
|
||||||
this.ionPickerColChange.emit(this.col);
|
|
||||||
}
|
|
||||||
|
|
||||||
private setSelected(selectedIndex: number, duration: number) {
|
private setSelected(selectedIndex: number, duration: number) {
|
||||||
// if there is a selected index, then figure out it's y position
|
// if there is a selected index, then figure out it's y position
|
||||||
// if there isn't a selected index, then just use the top y position
|
// if there isn't a selected index, then just use the top y position
|
||||||
@ -112,8 +98,6 @@ export class PickerColumnCmp implements ComponentInterface {
|
|||||||
// set what y position we're at
|
// set what y position we're at
|
||||||
cancelAnimationFrame(this.rafId);
|
cancelAnimationFrame(this.rafId);
|
||||||
this.update(y, duration, true);
|
this.update(y, duration, true);
|
||||||
|
|
||||||
this.emitColChange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private update(y: number, duration: number, saveY: boolean) {
|
private update(y: number, duration: number, saveY: boolean) {
|
||||||
@ -223,9 +207,6 @@ export class PickerColumnCmp implements ComponentInterface {
|
|||||||
if (notLockedIn) {
|
if (notLockedIn) {
|
||||||
// isn't locked in yet, keep decelerating until it is
|
// isn't locked in yet, keep decelerating until it is
|
||||||
this.rafId = requestAnimationFrame(() => this.decelerate());
|
this.rafId = requestAnimationFrame(() => this.decelerate());
|
||||||
} else {
|
|
||||||
this.velocity = 0;
|
|
||||||
this.emitColChange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (this.y % this.optHeight !== 0) {
|
} else if (this.y % this.optHeight !== 0) {
|
||||||
@ -296,12 +277,10 @@ export class PickerColumnCmp implements ComponentInterface {
|
|||||||
if (this.bounceFrom > 0) {
|
if (this.bounceFrom > 0) {
|
||||||
// bounce back up
|
// bounce back up
|
||||||
this.update(this.minY, 100, true);
|
this.update(this.minY, 100, true);
|
||||||
this.emitColChange();
|
|
||||||
return;
|
return;
|
||||||
} else if (this.bounceFrom < 0) {
|
} else if (this.bounceFrom < 0) {
|
||||||
// bounce back down
|
// bounce back down
|
||||||
this.update(this.maxY, 100, true);
|
this.update(this.maxY, 100, true);
|
||||||
this.emitColChange();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,15 +308,6 @@ export class PickerColumnCmp implements ComponentInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Only update selected value if column has a
|
|
||||||
* velocity of 0. If it does not, then the
|
|
||||||
* column is animating might land on
|
|
||||||
* a value different than the value at
|
|
||||||
* selectedIndex
|
|
||||||
*/
|
|
||||||
if (this.velocity !== 0) { return; }
|
|
||||||
|
|
||||||
const selectedIndex = clamp(min, this.col.selectedIndex || 0, max);
|
const selectedIndex = clamp(min, this.col.selectedIndex || 0, max);
|
||||||
if (this.col.prevSelected !== selectedIndex || forceRefresh) {
|
if (this.col.prevSelected !== selectedIndex || forceRefresh) {
|
||||||
const y = (selectedIndex * this.optHeight) * -1;
|
const y = (selectedIndex * this.optHeight) * -1;
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { testPickerColumn } from '../test.utils';
|
|
||||||
|
|
||||||
const TEST_TYPE = 'standalone';
|
|
||||||
|
|
||||||
test('picker-column: standalone', async () => {
|
|
||||||
await testPickerColumn(TEST_TYPE, '#single-column-button');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('picker-column:multi-column standalone', async () => {
|
|
||||||
await testPickerColumn(TEST_TYPE, '#multiple-column-button');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('picker-column:rtl: standalone', async () => {
|
|
||||||
await testPickerColumn(TEST_TYPE, '#single-column-button', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('picker-column:multi-column:rtl standalone', async () => {
|
|
||||||
await testPickerColumn(TEST_TYPE, '#multiple-column-button', true);
|
|
||||||
});
|
|
@ -1,92 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html dir="ltr">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Picker Column - Standalone</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
||||||
<link href="../../../../../css/core.css" rel="stylesheet">
|
|
||||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
|
||||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
|
||||||
<script src="../../../../../dist/ionic.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<ion-picker-controller></ion-picker-controller>
|
|
||||||
<ion-button onclick="openPicker()" id="single-column-button">Open Single Column Picker</ion-button>
|
|
||||||
<ion-button onclick="openPicker(2, 5, multiColumnOptions)" id="multiple-column-button">Open Multi Column Picker</ion-button>
|
|
||||||
<script>
|
|
||||||
const pickerController = document.querySelector('ion-picker-controller');
|
|
||||||
const defaultColumnOptions = [
|
|
||||||
[
|
|
||||||
'Dog',
|
|
||||||
'Cat',
|
|
||||||
'Bird',
|
|
||||||
'Lizard',
|
|
||||||
'Chinchilla'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
const multiColumnOptions = [
|
|
||||||
[
|
|
||||||
'Minified',
|
|
||||||
'Responsive',
|
|
||||||
'Full Stack',
|
|
||||||
'Mobile First',
|
|
||||||
'Serverless'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'Tomato',
|
|
||||||
'Avocado',
|
|
||||||
'Onion',
|
|
||||||
'Potato',
|
|
||||||
'Artichoke'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
async function openPicker(numColumns = 1, numOptions = 5, columnOptions = defaultColumnOptions) {
|
|
||||||
const picker = await pickerController.create({
|
|
||||||
columns: this.getColumns(numColumns, numOptions, columnOptions),
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
text: 'Cancel',
|
|
||||||
role: 'cancel'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Confirm',
|
|
||||||
handler: (value) => {
|
|
||||||
console.log(`Got Value ${value}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
await picker.present();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getColumns(numColumns, numOptions, columnOptions) {
|
|
||||||
let columns = [];
|
|
||||||
for (let i = 0; i < numColumns; i++) {
|
|
||||||
columns.push({
|
|
||||||
name: `col-${i}`,
|
|
||||||
options: this.getColumnOptions(i, numOptions, columnOptions)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getColumnOptions(columnIndex, numOptions, columnOptions) {
|
|
||||||
let options = [];
|
|
||||||
for (let i = 0; i < numOptions; i++) {
|
|
||||||
options.push({
|
|
||||||
text: columnOptions[columnIndex][i % numOptions],
|
|
||||||
value: i
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,60 +0,0 @@
|
|||||||
import { newE2EPage } from '@stencil/core/testing';
|
|
||||||
|
|
||||||
import { cleanScreenshotName, dragElementBy, generateE2EUrl, listenForEvent, waitForFunctionTestContext } from '../../../utils/test/utils';
|
|
||||||
|
|
||||||
export async function testPickerColumn(
|
|
||||||
type: string,
|
|
||||||
selector: string,
|
|
||||||
rtl = false,
|
|
||||||
screenshotName: string = cleanScreenshotName(selector)
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
const pageUrl = generateE2EUrl('picker-column', type, rtl);
|
|
||||||
if (rtl) {
|
|
||||||
screenshotName = `${screenshotName} rtl`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const page = await newE2EPage({
|
|
||||||
url: pageUrl
|
|
||||||
});
|
|
||||||
|
|
||||||
const screenshotCompares = [];
|
|
||||||
|
|
||||||
const openButton = await page.find(selector);
|
|
||||||
await openButton.click();
|
|
||||||
await page.waitFor(250);
|
|
||||||
|
|
||||||
screenshotCompares.push(await page.compareScreenshot(`${screenshotName}`));
|
|
||||||
|
|
||||||
// Setup counter
|
|
||||||
let colChangeCounter: any;
|
|
||||||
|
|
||||||
// Expose an event callback method
|
|
||||||
const COL_CHANGE = 'onIonPickerColChange';
|
|
||||||
await page.exposeFunction(COL_CHANGE, () => {
|
|
||||||
colChangeCounter.count += 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
const columns = await page.$$('ion-picker-column');
|
|
||||||
for (const column of Array.from(columns)) {
|
|
||||||
colChangeCounter = { count: 0 };
|
|
||||||
|
|
||||||
// Attach a listener to element with a callback
|
|
||||||
await listenForEvent(page, 'ionPickerColChange', column, COL_CHANGE);
|
|
||||||
|
|
||||||
// Simulate a column drag
|
|
||||||
await dragElementBy(column, page, 0, 100);
|
|
||||||
|
|
||||||
// Wait for ionPickerColChange event to be emitted once
|
|
||||||
await waitForFunctionTestContext((payload: any) => {
|
|
||||||
return payload.colChangeCounter.count === 1;
|
|
||||||
}, { colChangeCounter });
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const screenshotCompare of screenshotCompares) {
|
|
||||||
expect(screenshotCompare).toMatchScreenshot();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,77 +13,3 @@ export function cleanScreenshotName(screenshotName: string): string {
|
|||||||
.replace(/[^0-9a-zA-Z\s]/gi, '')
|
.replace(/[^0-9a-zA-Z\s]/gi, '')
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Listens for an event and fires a callback
|
|
||||||
* @param page - The Puppeteer `page` object
|
|
||||||
* @param eventType: string - The event name to listen for. ex: `ionPickerColChange`
|
|
||||||
* @param element: HTMLElement - An HTML element
|
|
||||||
* @param callbackName: string - The name of the callback function to
|
|
||||||
* call when the event is fired.
|
|
||||||
*
|
|
||||||
* Note: The callback function must be added using
|
|
||||||
* page.exposeFunction prior to calling this function.
|
|
||||||
*/
|
|
||||||
export const listenForEvent = async (page: any, eventType: string, element: any, callbackName: string): Promise<any> => {
|
|
||||||
try {
|
|
||||||
return await page.evaluate((scopeEventType: string, scopeElement: any, scopeCallbackName: string) => {
|
|
||||||
scopeElement.addEventListener(scopeEventType, (e: any) => {
|
|
||||||
(window as any)[scopeCallbackName](e);
|
|
||||||
});
|
|
||||||
}, eventType, element, callbackName);
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drags an element by (x, y) pixels
|
|
||||||
* @param element: HTMLElement - The HTML Element to drag
|
|
||||||
* @param page - The Puppeteer 'page' object
|
|
||||||
* @param x: number - Amount to drag `element` by on the x-axis
|
|
||||||
* @param y: number - Amount to drag `element` by on the y-axis
|
|
||||||
*/
|
|
||||||
export const dragElementBy = async (element: any, page: any, x = 0, y = 0): Promise<void> => {
|
|
||||||
try {
|
|
||||||
const boundingBox = await element.boundingBox();
|
|
||||||
|
|
||||||
const startX = boundingBox.x + boundingBox.width / 2;
|
|
||||||
const startY = boundingBox.y + boundingBox.height / 2;
|
|
||||||
|
|
||||||
const endX = startX + x;
|
|
||||||
const endY = startY + y;
|
|
||||||
|
|
||||||
const midX = endX / 2;
|
|
||||||
const midY = endY / 2;
|
|
||||||
|
|
||||||
await page.mouse.move(startX, startY);
|
|
||||||
await page.mouse.down();
|
|
||||||
await page.mouse.move(midX, midY);
|
|
||||||
await page.mouse.move(endX, endY);
|
|
||||||
await page.mouse.up();
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for a function to return true
|
|
||||||
* This method runs in the context of the
|
|
||||||
* test whereas page.waitForFunction runs in
|
|
||||||
* the context of the browser
|
|
||||||
* @param fn - The function to run
|
|
||||||
* @param params: any - Any parameters that the fn needs
|
|
||||||
* @param interval: number - Interval to run setInterval on
|
|
||||||
*/
|
|
||||||
export const waitForFunctionTestContext = async (fn: any, params: any, interval = 16): Promise<any> => {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const intervalId = setInterval(() => {
|
|
||||||
if (fn(params)) {
|
|
||||||
clearInterval(intervalId);
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
}, interval);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
Reference in New Issue
Block a user