mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
7 Commits
dev-build-
...
v4.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd1f207db5 | ||
|
|
cc91da867e | ||
|
|
3a9b679962 | ||
|
|
2bdaadddfb | ||
|
|
644f9f4627 | ||
|
|
e27bb2e862 | ||
|
|
f9f1775241 |
17
.github/PROCESS.md
vendored
17
.github/PROCESS.md
vendored
@@ -35,26 +35,27 @@ Issues and pull requests that need review. Pull requests will automatically move
|
||||
|
||||
Issues and pull requests that are completed. Issues will automatically move here when they are closed. Pull requests will automatically moved here when they are merged or closed with unmerged commits.
|
||||
|
||||
|
||||
## Managing Issues
|
||||
|
||||
### Issues to Triage
|
||||
|
||||
The issues that need to be triaged all have the `triage` label. In many cases the issue can be automatically processed by the Ionic Issue Bot by applying a specific label.
|
||||
|
||||
Once another label is applied to the issue, the `triage` label is automatically be removed by the bot.
|
||||
Once another label is applied to the issue, the `triage` label is automatically removed by the bot.
|
||||
|
||||
### Wrong Repo
|
||||
### Wrong Repository
|
||||
|
||||
If an issue does not pertain to the Ionic Framework but does pertain to another repo, it should be moved to that repo. The bot has been set up to automatically create the issue in other repositories while closing and locking the issue in this repository. Use one of the following labels to perform that action:
|
||||
If an issue does not pertain to the Ionic Framework but does pertain to another repository, it should be moved to that repository. The bot has been set up to automatically create the issue in other repositories while closing and locking the issue in this repository. Use one of the following labels to perform that action:
|
||||
|
||||
- ionitron: cli
|
||||
- ionitron: docs
|
||||
- ionitron: stencil
|
||||
- ionitron: native
|
||||
|
||||
### Ionic Pro Issues
|
||||
### Ionic Appflow Issues
|
||||
|
||||
If the issue is associated with Ionic Pro the submitter should be told to use the [Ionic Pro Support Forum](https://ionic.zendesk.com/hc/en-us/requests/new). The issue should be closed and locked. Use the `ionitron: ionic pro` label to accomplish this.
|
||||
If the issue is associated with Ionic Appflow the submitter should be told to use the [Ionic Appflow Support Forum](https://ionic.zendesk.com/hc/en-us/requests/new). The issue should be closed and locked. Use the `ionitron: ionic appflow` label to accomplish this.
|
||||
|
||||
### Support Questions
|
||||
|
||||
@@ -68,12 +69,12 @@ If the issue template has not been filled out completely, the issue should be cl
|
||||
|
||||
In many cases, the template is mostly filled out but just missing a thing or two or you may have a question or need clarification. In such a case, the submitter should be asked to supply that information.
|
||||
|
||||
1. create a comment requesting the additional information or clarification
|
||||
1. add the `needs reply` label to the task
|
||||
1. add a comment requesting the additional information or clarification
|
||||
1. add the `needs: reply` label to the task
|
||||
|
||||
NOTE: be sure to perform those actions in the order stated. If you add the comment second it will trigger the removal of the label.
|
||||
|
||||
If there is a response to the question, the bot will remove the `needs reply` and apply the `triage` label. The issue will then go through the triage handling again.
|
||||
If there is a response to the question, the bot will remove the `needs: reply` and apply the `triage` label. The issue will then go through the triage handling again.
|
||||
|
||||
if there is no response within 30 days, the issue will be closed and locked.
|
||||
|
||||
|
||||
@@ -37,9 +37,9 @@ function checkGit(tasks) {
|
||||
{
|
||||
title: 'Check current branch',
|
||||
task: () => execa.stdout('git', ['symbolic-ref', '--short', 'HEAD']).then(branch => {
|
||||
if (branch !== 'master') {
|
||||
throw new Error(`Not on "master" branch`);
|
||||
}
|
||||
// if (branch !== 'master') {
|
||||
// throw new Error(`Not on "master" branch`);
|
||||
// }
|
||||
})
|
||||
},
|
||||
{
|
||||
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,3 +1,19 @@
|
||||
## [4.0.2](https://github.com/ionic-team/ionic/compare/v4.0.1...v4.0.2) (2019-02-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** show proper shade for activated button on ios ([#17508](https://github.com/ionic-team/ionic/issues/17508)) ([3a9b679](https://github.com/ionic-team/ionic/commit/3a9b679)), closes [#17436](https://github.com/ionic-team/ionic/issues/17436)
|
||||
* **config:** update types for scrollPadding, inputBlurring and hideCaretOnScroll to boolean ([#17302](https://github.com/ionic-team/ionic/issues/17302)) ([39fbc32](https://github.com/ionic-team/ionic/commit/39fbc32))
|
||||
* **datetime:** default to current date when no value given ([#17443](https://github.com/ionic-team/ionic/issues/17443)) ([644f9f4](https://github.com/ionic-team/ionic/commit/644f9f4))
|
||||
* **item-sliding:** Sliding no longer breaks after removing an item ([#17492](https://github.com/ionic-team/ionic/issues/17492)) ([e27bb2e](https://github.com/ionic-team/ionic/commit/e27bb2e))
|
||||
* **range:** implement RTL (from PR 17157) ([#17384](https://github.com/ionic-team/ionic/issues/17384)) ([4f203bc](https://github.com/ionic-team/ionic/commit/4f203bc)), closes [#17012](https://github.com/ionic-team/ionic/issues/17012)
|
||||
* **searchbar:** allow setting of toolbar color and searchbar color ([#17474](https://github.com/ionic-team/ionic/issues/17474)) ([ba4e117](https://github.com/ionic-team/ionic/commit/ba4e117))
|
||||
* **select:** Account for when options are not loaded immediately ([#17405](https://github.com/ionic-team/ionic/issues/17405)) ([f9f1775](https://github.com/ionic-team/ionic/commit/f9f1775))
|
||||
* **tab-bar:** add translucent tab-bar styles back ([#17376](https://github.com/ionic-team/ionic/issues/17376)) ([374bd77](https://github.com/ionic-team/ionic/commit/374bd77))
|
||||
|
||||
|
||||
|
||||
## [4.0.1](https://github.com/ionic-team/ionic/compare/v4.0.0...v4.0.1) (2019-02-06)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.2",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -45,7 +45,7 @@
|
||||
"css/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/core": "4.0.1",
|
||||
"@ionic/core": "4.0.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -23,8 +23,8 @@ The Ionic Core package contains the Web Components that make up the reusable UI
|
||||
Easiest way to start using Ionic Core is by adding a script tag to the CDN:
|
||||
|
||||
```html
|
||||
<link href="https://unpkg.com/@ionic/core@4.0.1/css/ionic.bundle.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/@ionic/core@4.0.1/dist/ionic.js"></script>
|
||||
<link href="https://unpkg.com/@ionic/core@4.0.2/css/ionic.bundle.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/@ionic/core@4.0.2/dist/ionic.js"></script>
|
||||
```
|
||||
|
||||
Any Ionic component added to the webpage will automatically load. This includes writing the component tag directly in HTML, or using JavaScript such as `document.createElement('ion-toggle')`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.2",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
--opacity: #{$button-ios-opacity-activated};
|
||||
}
|
||||
|
||||
:host(.button-solid.activated.ion-color) .button-native {
|
||||
background: current-color(shade);
|
||||
}
|
||||
|
||||
// iOS Outline Button
|
||||
// --------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
/**
|
||||
* Gets a date value given a format
|
||||
* Defaults to the current date if
|
||||
* no date given
|
||||
*/
|
||||
export function getDateValue(date: DatetimeData, format: string): number {
|
||||
const getValue = getValueFromFormat(date, format);
|
||||
|
||||
if (getValue) { return getValue; }
|
||||
|
||||
const defaultDate = parseDate(new Date().toISOString());
|
||||
return getValueFromFormat((defaultDate as DatetimeData), format);
|
||||
}
|
||||
|
||||
export function renderDatetime(template: string, value: DatetimeData | undefined, locale: LocaleData): string | undefined {
|
||||
if (value === undefined) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { DatetimeChangeEventDetail, DatetimeOptions, Mode, PickerColumn, PickerC
|
||||
import { clamp, findItemLabel, renderHiddenInput } from '../../utils/helpers';
|
||||
import { hostContext } from '../../utils/theme';
|
||||
|
||||
import { DatetimeData, LocaleData, convertDataToISO, convertFormatToKey, convertToArrayOfNumbers, convertToArrayOfStrings, dateDataSortValue, dateSortValue, dateValueRange, daysInMonth, getValueFromFormat, parseDate, parseTemplate, renderDatetime, renderTextFormat, updateDate } from './datetime-util';
|
||||
import { DatetimeData, LocaleData, convertDataToISO, convertFormatToKey, convertToArrayOfNumbers, convertToArrayOfStrings, dateDataSortValue, dateSortValue, dateValueRange, daysInMonth, getDateValue, parseDate, parseTemplate, renderDatetime, renderTextFormat, updateDate } from './datetime-util';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-datetime',
|
||||
@@ -359,7 +359,7 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
// cool, we've loaded up the columns with options
|
||||
// preselect the option for this column
|
||||
const optValue = getValueFromFormat(this.datetimeValue, format);
|
||||
const optValue = getDateValue(this.datetimeValue, format);
|
||||
const selectedIndex = colOptions.findIndex(opt => opt.value === optValue);
|
||||
|
||||
return {
|
||||
|
||||
35
core/src/components/datetime/test/datetime.spec.ts
Normal file
35
core/src/components/datetime/test/datetime.spec.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { DatetimeOptions } from '../datetime-interface';
|
||||
import { DatetimeData, getDateValue } from '../datetime-util';
|
||||
|
||||
describe('Datetime', () => {
|
||||
describe('getDateValue()', () => {
|
||||
it('it should return the date value for the current day', () => {
|
||||
const today = new Date();
|
||||
|
||||
const dayValue = getDateValue({}, 'DD');
|
||||
const monthvalue = getDateValue({}, 'MM');
|
||||
const yearValue = getDateValue({}, 'YYYY');
|
||||
|
||||
expect(dayValue).toEqual(today.getDate());
|
||||
expect(monthvalue).toEqual(today.getMonth() + 1);
|
||||
expect(yearValue).toEqual(today.getFullYear());
|
||||
});
|
||||
|
||||
it('it should return the date value for a given day', () => {
|
||||
const date = new Date('15 October 1995');
|
||||
const dateTimeData: DatetimeData = {
|
||||
year: date.getFullYear(),
|
||||
month: date.getMonth() + 1,
|
||||
day: date.getDate()
|
||||
}
|
||||
|
||||
const dayValue = getDateValue(dateTimeData, 'DD');
|
||||
const monthvalue = getDateValue(dateTimeData, 'MM');
|
||||
const yearValue = getDateValue(dateTimeData, 'YYYY');
|
||||
|
||||
expect(dayValue).toEqual(date.getDate());
|
||||
expect(monthvalue).toEqual(date.getMonth() + 1);
|
||||
expect(yearValue).toEqual(date.getFullYear());
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -66,7 +66,6 @@ export class ItemSliding implements ComponentInterface {
|
||||
|
||||
async componentDidLoad() {
|
||||
this.item = this.el.querySelector('ion-item');
|
||||
|
||||
await this.updateOptions();
|
||||
|
||||
this.gesture = (await import('../../utils/gesture')).createGesture({
|
||||
@@ -91,6 +90,7 @@ export class ItemSliding implements ComponentInterface {
|
||||
|
||||
this.item = null;
|
||||
this.leftOptions = this.rightOptions = undefined;
|
||||
this.closeOpened();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,6 +128,7 @@ export class ItemSliding implements ComponentInterface {
|
||||
async closeOpened(): Promise<boolean> {
|
||||
if (openSlidingItem !== undefined) {
|
||||
openSlidingItem.close();
|
||||
openSlidingItem = undefined;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -162,6 +163,7 @@ export class ItemSliding implements ComponentInterface {
|
||||
this.closeOpened();
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!(this.rightOptions || this.leftOptions);
|
||||
}
|
||||
|
||||
|
||||
49
core/src/components/item-sliding/test/interactive/e2e.ts
Normal file
49
core/src/components/item-sliding/test/interactive/e2e.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
test('item-sliding: interactive', async () => {
|
||||
const page = await newE2EPage({
|
||||
url: '/src/components/item-sliding/test/interactive?ionic:_testing=true'
|
||||
});
|
||||
|
||||
const compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
|
||||
const items = await page.$$('ion-item-sliding');
|
||||
expect(items.length).toEqual(3);
|
||||
|
||||
await slideAndDelete(items[0], page);
|
||||
|
||||
const itemsAfterFirstSlide = await page.$$('ion-item-sliding');
|
||||
expect(itemsAfterFirstSlide.length).toEqual(2);
|
||||
|
||||
await slideAndDelete(items[1], page);
|
||||
|
||||
const itemsAfterSecondSlide = await page.$$('ion-item-sliding');
|
||||
expect(itemsAfterSecondSlide.length).toEqual(1);
|
||||
});
|
||||
|
||||
async function slideAndDelete(item: any, page: any) {
|
||||
try {
|
||||
// Get the element's ID
|
||||
const id = await(await item.getProperty('id')).jsonValue();
|
||||
|
||||
// Simulate a drag
|
||||
const boundingBox = await item.boundingBox();
|
||||
const centerX = parseFloat(boundingBox.x + boundingBox.width / 2);
|
||||
const centerY = parseFloat(boundingBox.y + boundingBox.height / 2);
|
||||
|
||||
await page.mouse.move(centerX, centerY);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(0, centerY);
|
||||
await page.mouse.up();
|
||||
|
||||
// Click the "delete" option
|
||||
const options = await item.$$('ion-item-option');
|
||||
await options[0].click();
|
||||
|
||||
// Wait for element to be removed from DOM
|
||||
await page.waitForSelector(id, { hidden: true });
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
54
core/src/components/item-sliding/test/interactive/index.html
Normal file
54
core/src/components/item-sliding/test/interactive/index.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Item Sliding - 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-list></ion-list>
|
||||
|
||||
<script>
|
||||
let lists = document.getElementsByTagName('ion-list');
|
||||
for (var i = 0; i < lists.length; i++) {
|
||||
for (var j = 0; j < 3; j++) {
|
||||
addSlidingItem(lists[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function addSlidingItem(list) {
|
||||
const slidingItem = document.createElement('ion-item-sliding');
|
||||
slidingItem.innerHTML = `
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<h2>Item Options Both Sides</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-options side="end">
|
||||
<ion-item-option color="danger" expandable onclick="remove(this)">
|
||||
<ion-icon name="trash"></ion-icon>
|
||||
Delete
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
`;
|
||||
|
||||
|
||||
slidingItem.id = `item-${list.childElementCount}`;
|
||||
|
||||
list.appendChild(slidingItem);
|
||||
}
|
||||
|
||||
function remove(optionElement) {
|
||||
const slidingElement = optionElement.parentNode.parentNode;
|
||||
lists[0].removeChild(slidingElement);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -133,8 +133,21 @@ export class Select implements ComponentInterface {
|
||||
@Listen('ionSelectOptionDidUnload')
|
||||
async selectOptionChanged() {
|
||||
await this.loadOptions();
|
||||
|
||||
if (this.didInit) {
|
||||
this.updateOptions();
|
||||
|
||||
/**
|
||||
* In the event that options
|
||||
* are not loaded at component load
|
||||
* this ensures that any value that is
|
||||
* set is properly rendered once
|
||||
* options have been loaded
|
||||
*/
|
||||
if (this.value !== undefined) {
|
||||
this.el.forceUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
core/src/components/select/test/async/e2e.ts
Normal file
10
core/src/components/select/test/async/e2e.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
test('select: async', async () => {
|
||||
const page = await newE2EPage({
|
||||
url: '/src/components/select/test/async?ionic:_testing=true'
|
||||
});
|
||||
|
||||
const compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
});
|
||||
37
core/src/components/select/test/async/index.html
Normal file
37
core/src/components/select/test/async/index.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Select - Async</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-select id="animals" placeholder="Select One"></ion-select>
|
||||
|
||||
<script>
|
||||
let select = document.getElementById('animals');
|
||||
const options = ['bird', 'dog', 'shark', 'lizard'];
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
options.forEach(option => {
|
||||
let o = document.createElement('ion-select-option');
|
||||
o.value = option;
|
||||
o.textContent = option;
|
||||
|
||||
select.appendChild(o);
|
||||
});
|
||||
|
||||
select.value = options[0];
|
||||
|
||||
}, 500);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.2",
|
||||
"description": "Pre-packaged API documentation for the Ionic docs.",
|
||||
"main": "core.json",
|
||||
"files": [
|
||||
|
||||
Reference in New Issue
Block a user