FIX: Deprecate NumberField, use <input> instead (#25434)
* Revert "FEATURE: Use native number fields for integer inputs (#24984)"
This reverts commit 8fce890ead
.
* FIX: Deprecate NumberField, use <input> instead
This reverts #24984 as it introduced regressions (behavioral and visual) and instead it deprecates the NumberField component and replaces its uses in core with native `<input>` elements.
This commit is contained in:
parent
19b86e7ea2
commit
f2e1363f67
|
@ -1,8 +1,9 @@
|
||||||
<NumberField
|
<input
|
||||||
@value={{this.value}}
|
{{on "input" (action (mut this.value) value="target.value")}}
|
||||||
@classNames="input-setting-integer"
|
value={{this.value}}
|
||||||
@min={{if this.setting.min this.setting.min null}}
|
min={{if this.setting.min this.setting.min null}}
|
||||||
@max={{if this.setting.max this.setting.max null}}
|
max={{if this.setting.max this.setting.max null}}
|
||||||
|
class="input-setting-integer"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SettingValidationMessage @message={{this.validationMessage}} />
|
<SettingValidationMessage @message={{this.validationMessage}} />
|
||||||
|
|
|
@ -4,10 +4,15 @@
|
||||||
<label for="category-position">
|
<label for="category-position">
|
||||||
{{i18n "category.position"}}
|
{{i18n "category.position"}}
|
||||||
</label>
|
</label>
|
||||||
<NumberField
|
<input
|
||||||
@value={{this.category.position}}
|
{{on
|
||||||
@id="category-position"
|
"input"
|
||||||
@min="0"
|
(action (mut this.category.position) value="target.value")
|
||||||
|
}}
|
||||||
|
value={{this.category.position}}
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
id="category-position"
|
||||||
class="position-input"
|
class="position-input"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
@ -34,10 +39,15 @@
|
||||||
{{i18n "category.num_featured_topics"}}
|
{{i18n "category.num_featured_topics"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</label>
|
</label>
|
||||||
<NumberField
|
<input
|
||||||
@value={{this.category.num_featured_topics}}
|
{{on
|
||||||
@id="category-number-featured-topics"
|
"input"
|
||||||
@min="1"
|
(action (mut this.category.num_featured_topics) value="target.value")
|
||||||
|
}}
|
||||||
|
value={{this.category.num_featured_topics}}
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
id="category-number-featured-topics"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -184,10 +194,18 @@
|
||||||
<label for="category-number-daily-bump">
|
<label for="category-number-daily-bump">
|
||||||
{{i18n "category.num_auto_bump_daily"}}
|
{{i18n "category.num_auto_bump_daily"}}
|
||||||
</label>
|
</label>
|
||||||
<NumberField
|
<input
|
||||||
@value={{this.category.category_setting.num_auto_bump_daily}}
|
{{on
|
||||||
@id="category-number-daily-bump"
|
"input"
|
||||||
@min="0"
|
(action
|
||||||
|
(mut this.category.category_setting.num_auto_bump_daily)
|
||||||
|
value="target.value"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
value={{this.category.category_setting.num_auto_bump_daily}}
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
id="category-number-daily-bump"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -195,10 +213,18 @@
|
||||||
<label for="category-auto-bump-cooldown-days">
|
<label for="category-auto-bump-cooldown-days">
|
||||||
{{i18n "category.auto_bump_cooldown_days"}}
|
{{i18n "category.auto_bump_cooldown_days"}}
|
||||||
</label>
|
</label>
|
||||||
<NumberField
|
<input
|
||||||
@value={{this.category.category_setting.auto_bump_cooldown_days}}
|
{{on
|
||||||
@id="category-auto-bump-cooldown-days"
|
"input"
|
||||||
@min="0"
|
(action
|
||||||
|
(mut this.category.category_setting.auto_bump_cooldown_days)
|
||||||
|
value="target.value"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
value={{this.category.category_setting.auto_bump_cooldown_days}}
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
id="category-auto-bump-cooldown-days"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -20,10 +20,14 @@
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<div class="reorder-categories-actions">
|
<div class="reorder-categories-actions">
|
||||||
<NumberField
|
<input
|
||||||
@value={{readonly category.position}}
|
{{on
|
||||||
@change={{fn this.change category}}
|
"input"
|
||||||
@min="0"
|
(action (fn this.change category) value="target.value")
|
||||||
|
}}
|
||||||
|
value={{category.position}}
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
/>
|
/>
|
||||||
<DButton
|
<DButton
|
||||||
@action={{fn this.move category -1}}
|
@action={{fn this.move category -1}}
|
||||||
|
|
|
@ -134,12 +134,13 @@ export default class ReorderCategories extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
change(category, event) {
|
change(category, newPosition) {
|
||||||
let newPosition = parseFloat(event.target.value);
|
newPosition = parseInt(newPosition, 10);
|
||||||
newPosition =
|
newPosition =
|
||||||
newPosition < category.get("position")
|
newPosition < category.get("position")
|
||||||
? Math.ceil(newPosition)
|
? Math.ceil(newPosition)
|
||||||
: Math.floor(newPosition);
|
: Math.floor(newPosition);
|
||||||
|
|
||||||
const direction = newPosition - category.get("position");
|
const direction = newPosition - category.get("position");
|
||||||
this.move(category, direction);
|
this.move(category, direction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
<Input
|
|
||||||
id={{@id}}
|
|
||||||
class={{@classNames}}
|
|
||||||
min={{@min}}
|
|
||||||
max={{@max}}
|
|
||||||
@type="number"
|
|
||||||
@value={{@value}}
|
|
||||||
/>
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import TextField from "discourse/components/text-field";
|
||||||
|
import { allowOnlyNumericInput } from "discourse/lib/utilities";
|
||||||
|
import deprecated from "discourse-common/lib/deprecated";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
|
export default TextField.extend({
|
||||||
|
classNameBindings: ["invalid"],
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super(...arguments);
|
||||||
|
deprecated(
|
||||||
|
`NumberField component is deprecated. Use native <input> elements instead.\ne.g. <input {{on "input" (action (mut this.value) value="target.value")}} type="number" value={{this.value}} />`,
|
||||||
|
{
|
||||||
|
id: "discourse.number-field",
|
||||||
|
since: "3.2.0.beta5",
|
||||||
|
dropFrom: "3.3.0",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
keyDown: function (event) {
|
||||||
|
allowOnlyNumericInput(event, this._minNumber && this._minNumber < 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
get _minNumber() {
|
||||||
|
if (!this.get("min")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return parseInt(this.get("min"), 10);
|
||||||
|
},
|
||||||
|
|
||||||
|
get _maxNumber() {
|
||||||
|
if (!this.get("max")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return parseInt(this.get("max"), 10);
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("number")
|
||||||
|
value: {
|
||||||
|
get(number) {
|
||||||
|
return parseInt(number, 10);
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
const num = parseInt(value, 10);
|
||||||
|
if (isNaN(num)) {
|
||||||
|
this.set("invalid", true);
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
this.set("invalid", false);
|
||||||
|
this.set("number", num);
|
||||||
|
return num.toString();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("placeholderKey")
|
||||||
|
placeholder(key) {
|
||||||
|
return key ? I18n.t(key) : "";
|
||||||
|
},
|
||||||
|
});
|
|
@ -2,6 +2,7 @@ import { fillIn, render, triggerKeyEvent } from "@ember/test-helpers";
|
||||||
import { hbs } from "ember-cli-htmlbars";
|
import { hbs } from "ember-cli-htmlbars";
|
||||||
import { module, test } from "qunit";
|
import { module, test } from "qunit";
|
||||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||||
|
import { withSilencedDeprecationsAsync } from "discourse-common/lib/deprecated";
|
||||||
|
|
||||||
module("Integration | Component | number-field", function (hooks) {
|
module("Integration | Component | number-field", function (hooks) {
|
||||||
setupRenderingTest(hooks);
|
setupRenderingTest(hooks);
|
||||||
|
@ -9,9 +10,11 @@ module("Integration | Component | number-field", function (hooks) {
|
||||||
test("number field", async function (assert) {
|
test("number field", async function (assert) {
|
||||||
this.set("value", 123);
|
this.set("value", 123);
|
||||||
|
|
||||||
await render(hbs`
|
await withSilencedDeprecationsAsync("discourse.number-field", async () => {
|
||||||
<NumberField @value={{this.value}} @classNames="number-field-test" />
|
await render(hbs`
|
||||||
`);
|
<NumberField @value={{this.value}} @classNames="number-field-test" />
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
await fillIn(".number-field-test", "33");
|
await fillIn(".number-field-test", "33");
|
||||||
|
|
||||||
|
@ -34,9 +37,11 @@ module("Integration | Component | number-field", function (hooks) {
|
||||||
test("number field | min value", async function (assert) {
|
test("number field | min value", async function (assert) {
|
||||||
this.set("value", "");
|
this.set("value", "");
|
||||||
|
|
||||||
await render(hbs`
|
await withSilencedDeprecationsAsync("discourse.number-field", async () => {
|
||||||
<NumberField @value={{this.value}} @classNames="number-field-test" @min="1" />
|
await render(hbs`
|
||||||
`);
|
<NumberField @value={{this.value}} @classNames="number-field-test" @min="1" />
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
await triggerKeyEvent(".number-field-test", "keydown", 189); // -
|
await triggerKeyEvent(".number-field-test", "keydown", 189); // -
|
||||||
await triggerKeyEvent(".number-field-test", "keydown", 49); // 1
|
await triggerKeyEvent(".number-field-test", "keydown", 49); // 1
|
||||||
|
@ -47,9 +52,11 @@ module("Integration | Component | number-field", function (hooks) {
|
||||||
"value is cleared when the input is less than the min"
|
"value is cleared when the input is less than the min"
|
||||||
);
|
);
|
||||||
|
|
||||||
await render(hbs`
|
await withSilencedDeprecationsAsync("discourse.number-field", async () => {
|
||||||
<NumberField @value={{this.value}} @classNames="number-field-test" @min="-10" />
|
await render(hbs`
|
||||||
`);
|
<NumberField @value={{this.value}} @classNames="number-field-test" @min="-10" />
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
await fillIn(".number-field-test", "-1");
|
await fillIn(".number-field-test", "-1");
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ module("Unit | Component | reorder-categories", function (hooks) {
|
||||||
site.set("categories", [elem1, elem2, elem3]);
|
site.set("categories", [elem1, elem2, elem3]);
|
||||||
|
|
||||||
// Move category 'foo' from position 0 to position 2
|
// Move category 'foo' from position 0 to position 2
|
||||||
component.change(elem1, { target: { value: "2" } });
|
component.change(elem1, "2");
|
||||||
|
|
||||||
assert.deepEqual(component.categoriesOrdered.mapBy("slug"), [
|
assert.deepEqual(component.categoriesOrdered.mapBy("slug"), [
|
||||||
"bar",
|
"bar",
|
||||||
|
@ -137,7 +137,7 @@ module("Unit | Component | reorder-categories", function (hooks) {
|
||||||
const site = getOwner(this).lookup("service:site");
|
const site = getOwner(this).lookup("service:site");
|
||||||
site.set("categories", [elem1, child1, elem2, elem3]);
|
site.set("categories", [elem1, child1, elem2, elem3]);
|
||||||
|
|
||||||
component.change(elem1, { target: { value: 3 } });
|
component.change(elem1, "3");
|
||||||
|
|
||||||
assert.deepEqual(component.categoriesOrdered.mapBy("slug"), [
|
assert.deepEqual(component.categoriesOrdered.mapBy("slug"), [
|
||||||
"bar",
|
"bar",
|
||||||
|
|
Loading…
Reference in New Issue