mirror of https://github.com/status-im/consul.git
ui: {{phrase-editor}} amends (#5991)
1. Re-focus the input element on phrase removal 2. Move all actions to `actions:` 3. Move to a form looking `value` rather than `items` 4. Move placeholder functionalit yinto the component 5. Force DDAU instead of two way binding with `slice` and `onchange` 6. Begin to deprecate the `searchable` interface
This commit is contained in:
parent
6d8a706b4d
commit
62fa803d9f
|
@ -1,44 +1,67 @@
|
|||
import Component from '@ember/component';
|
||||
import { get, set } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default Component.extend({
|
||||
dom: service('dom'),
|
||||
classNames: ['phrase-editor'],
|
||||
item: '',
|
||||
remove: function(index, e) {
|
||||
this.items.removeAt(index, 1);
|
||||
didInsertElement: function() {
|
||||
this._super(...arguments);
|
||||
// TODO: use {{ref}}
|
||||
this.input = get(this, 'dom').element('input', this.element);
|
||||
},
|
||||
onchange: function(e) {},
|
||||
search: function(e) {
|
||||
// TODO: Temporarily continue supporting `searchable`
|
||||
let searchable = get(this, 'searchable');
|
||||
if (searchable) {
|
||||
if (!Array.isArray(searchable)) {
|
||||
searchable = [searchable];
|
||||
}
|
||||
searchable.forEach(item => {
|
||||
item.search(get(this, 'value'));
|
||||
});
|
||||
}
|
||||
this.onchange(e);
|
||||
},
|
||||
add: function(e) {
|
||||
const value = get(this, 'item').trim();
|
||||
if (value !== '') {
|
||||
set(this, 'item', '');
|
||||
const currentItems = get(this, 'items') || [];
|
||||
const items = new Set(currentItems).add(value);
|
||||
if (items.size > currentItems.length) {
|
||||
set(this, 'items', [...items]);
|
||||
this.onchange(e);
|
||||
oninput: function(e) {},
|
||||
onkeydown: function(e) {},
|
||||
actions: {
|
||||
keydown: function(e) {
|
||||
switch (e.keyCode) {
|
||||
case 8: // backspace
|
||||
if (e.target.value == '' && get(this, 'value').length > 0) {
|
||||
this.actions.remove.bind(this)(get(this, 'value').length - 1);
|
||||
}
|
||||
break;
|
||||
case 27: // escape
|
||||
set(this, 'value', []);
|
||||
this.search({ target: this });
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
onkeydown: function(e) {
|
||||
switch (e.keyCode) {
|
||||
case 8:
|
||||
if (e.target.value == '' && this.items.length > 0) {
|
||||
this.remove(this.items.length - 1);
|
||||
this.onkeydown({ target: this });
|
||||
},
|
||||
input: function(e) {
|
||||
set(this, 'item', e.target.value);
|
||||
this.oninput({ target: this });
|
||||
},
|
||||
remove: function(index, e) {
|
||||
get(this, 'value').removeAt(index, 1);
|
||||
this.search({ target: this });
|
||||
this.input.focus();
|
||||
},
|
||||
add: function(e) {
|
||||
const item = get(this, 'item').trim();
|
||||
if (item !== '') {
|
||||
set(this, 'item', '');
|
||||
const currentItems = get(this, 'value') || [];
|
||||
const items = new Set(currentItems).add(item);
|
||||
if (items.size > currentItems.length) {
|
||||
set(this, 'value', [...items]);
|
||||
this.search({ target: this });
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
oninput: function(e) {
|
||||
set(this, 'item', e.target.value);
|
||||
},
|
||||
onchange: function(e) {
|
||||
let searchable = get(this, 'searchable');
|
||||
if (!Array.isArray(searchable)) {
|
||||
searchable = [searchable];
|
||||
}
|
||||
searchable.forEach(item => {
|
||||
item.search(get(this, 'items'));
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -8,4 +8,5 @@
|
|||
padding: 0;
|
||||
height: 10px;
|
||||
margin-right: 3px;
|
||||
font-size: 0;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<ul>
|
||||
{{#each items as |item index|}}
|
||||
<li>
|
||||
<button type="button" onclick={{action remove index}}>Remove</button>{{item}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<label class="type-search">
|
||||
<ul>
|
||||
{{#each value as |item index|}}
|
||||
<li>
|
||||
<button type="button" {{action 'remove' index}}>Remove</button>{{item}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<label class="type-search">
|
||||
<span>Search</span>
|
||||
<input onchange={{action add}} onsearch={{action add}} oninput={{action oninput}} onkeydown={{action onkeydown}} placeholder="{{placeholder}}" value="{{item}}" type="search" name="s" autofocus="autofocus" />
|
||||
</label>
|
||||
<input onchange={{action 'add'}} onsearch={{action 'add'}} oninput={{action 'input'}} onkeydown={{action 'keydown'}} placeholder={{if (eq value.length 0) placeholder}} value={{item}} type="search" name="s" autofocus="autofocus" />
|
||||
</label>
|
|
@ -10,7 +10,12 @@
|
|||
{{/block-slot}}
|
||||
{{#block-slot 'toolbar'}}
|
||||
{{#if (gt items.length 0) }}
|
||||
{{#phrase-editor placeholder=(if (eq terms.length 0) 'service:name tag:name status:critical search-term' '') items=terms searchable=searchable}}{{/phrase-editor}}
|
||||
{{phrase-editor
|
||||
placeholder='service:name tag:name status:critical search-term'
|
||||
value=(slice 0 terms.length terms)
|
||||
onchange=(action (mut terms) value='target.value')
|
||||
searchable=searchable
|
||||
}}
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot 'content'}}
|
||||
|
|
|
@ -5,30 +5,45 @@ moduleForComponent('phrase-editor', 'Integration | Component | phrase editor', {
|
|||
integration: true,
|
||||
});
|
||||
|
||||
test('it renders', function(assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.on('myAction', function(val) { ... });
|
||||
|
||||
this.render(hbs`{{phrase-editor}}`);
|
||||
|
||||
assert.equal(
|
||||
test('it renders a phrase', function(assert) {
|
||||
this.set('value', ['phrase']);
|
||||
this.render(hbs`{{phrase-editor value=value}}`);
|
||||
assert.notEqual(
|
||||
this.$()
|
||||
.text()
|
||||
.trim(),
|
||||
'Search'
|
||||
);
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#phrase-editor}}
|
||||
template block text
|
||||
{{/phrase-editor}}
|
||||
`);
|
||||
|
||||
assert.equal(
|
||||
this.$()
|
||||
.text()
|
||||
.trim(),
|
||||
'Search'
|
||||
.trim()
|
||||
.indexOf('phrase'),
|
||||
-1
|
||||
);
|
||||
});
|
||||
test('it calls onchange when a phrase is removed by clicking the phrase remove button and refocuses', function(assert) {
|
||||
assert.expect(3);
|
||||
this.set('value', ['phrase']);
|
||||
this.on('change', function(e) {
|
||||
assert.equal(e.target.value.length, 0);
|
||||
});
|
||||
this.render(hbs`{{phrase-editor value=value onchange=(action 'change')}}`);
|
||||
assert.notEqual(
|
||||
this.$()
|
||||
.text()
|
||||
.trim()
|
||||
.indexOf('phrase'),
|
||||
-1
|
||||
);
|
||||
const $input = this.$('input');
|
||||
const $button = this.$('button');
|
||||
$button.trigger('click');
|
||||
assert.equal(document.activeElement, $input.get(0));
|
||||
});
|
||||
test('it calls onchange when a phrase is added', function(assert) {
|
||||
assert.expect(1);
|
||||
this.on('change', function(e) {
|
||||
assert.equal(e.target.value.length, 2);
|
||||
});
|
||||
this.set('value', ['phrase']);
|
||||
this.render(hbs`{{phrase-editor value=value onchange=(action 'change')}}`);
|
||||
const $input = this.$('input');
|
||||
$input.get(0).value = 'phrase 2';
|
||||
$input.trigger('input');
|
||||
$input.trigger('search');
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue