Skip to content

Commit

Permalink
remove correct item with backspace. Fixes #106
Browse files Browse the repository at this point in the history
  • Loading branch information
oyejorge committed Jun 2, 2021
1 parent 80df4d6 commit 18c7fb0
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 59 deletions.
4 changes: 2 additions & 2 deletions doc_src/pages/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ control.addItem('test');
<td>Retrieves the dom element for the option identified by the given value.</td>
</tr>
<tr>
<td><code>getAdjacent(dom_element, direction)</code></td>
<td><code>getAdjacent(HTMLElement, direction)</code></td>
<td>Retrieves the dom element for the previous or next option, relative to the currently highlighted option. The <code>direction</code> argument should be 1 for "next" or -1 for "previous".</td>
</tr>
<tr>
Expand Down Expand Up @@ -73,7 +73,7 @@ control.addItem('test');
<td>"Selects" an item. Adds it to the list at the current caret position. If <code>silent</code> is truthy, no change event will be fired on the original input.</td>
</tr>
<tr>
<td><code>removeItem(value, silent)</code></td>
<td><code>removeItem(value|HTMLElement, silent)</code></td>
<td>Removes the selected item matching the provided value. If <code>silent</code> is truthy, no change event will be fired on the original input.</td>
</tr>
<tr>
Expand Down
105 changes: 55 additions & 50 deletions src/tom-select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import MicroPlugin from './contrib/microplugin.js';
import Sifter from '@orchidjs/sifter/dist/esm/sifter.js';
import { escape_regex } from '@orchidjs/sifter/dist/esm/utils.js';
import { TomSettings } from './types/settings';
import { TomInput, TomArgObject, TomOption, TomOptions, TomCreateFilter, TomCreateCallback } from './types/index';
import { TomInput, TomArgObject, TomOption, TomOptions, TomCreateFilter, TomCreateCallback, TomItem } from './types/index';
import {highlight, removeHighlight} from './contrib/highlight.js';
import * as constants from './constants.js';
import getSettings from './getSettings.js';
Expand Down Expand Up @@ -77,7 +77,7 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
public loadedSearches : { [key: string]: boolean } = {};

public activeOption : null|HTMLElement = null;
public activeItems : HTMLElement[] = [];
public activeItems : TomItem[] = [];

public optgroups : TomOptions = {};
public options : TomOptions = {};
Expand Down Expand Up @@ -296,7 +296,7 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
addEvent(control,'click', (evt) => {

var target_match = parentMatch( evt.target as HTMLElement, '.'+self.settings.itemClass, control);
if( target_match && self.onItemSelect(evt as MouseEvent, target_match) ){
if( target_match && self.onItemSelect(evt as MouseEvent, target_match as TomItem) ){
preventDefault(evt,true);
return;
}
Expand Down Expand Up @@ -822,7 +822,7 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
* that has been selected.
*
*/
onItemSelect( evt?:MouseEvent, item?:HTMLElement ):boolean{
onItemSelect( evt?:MouseEvent, item?:TomItem ):boolean{
var self = this;

if( !self.isLocked && self.settings.mode === 'multi' ){
Expand Down Expand Up @@ -953,7 +953,7 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
* Sets the selected item.
*
*/
setActiveItem( item?:HTMLElement, e?:MouseEvent|KeyboardEvent ){
setActiveItem( item?:TomItem, e?:MouseEvent|KeyboardEvent ){
var self = this;
var eventName;
var i, begin, end, swap;
Expand Down Expand Up @@ -984,7 +984,7 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
end = swap;
}
for (i = begin; i <= end; i++) {
item = self.control.children[i] as HTMLElement;
item = self.control.children[i] as TomItem;
if (self.activeItems.indexOf(item) === -1) {
self.setActiveItemClass(item);
}
Expand Down Expand Up @@ -1012,7 +1012,7 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
* Set the active and last-active classes
*
*/
setActiveItemClass( item:HTMLElement ){
setActiveItemClass( item:TomItem ){

var last_active = this.control.querySelector('.last-active');
if( last_active ) removeClasses(last_active as HTMLElement,'last-active');
Expand All @@ -1027,7 +1027,7 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
* Remove active item
*
*/
removeActiveItem( item:HTMLElement ){
removeActiveItem( item:TomItem ){
var idx = this.activeItems.indexOf(item);
this.activeItems.splice(idx, 1);
removeClasses(item,'active');
Expand Down Expand Up @@ -1736,10 +1736,15 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
* matching the given value.
*
*/
getItem(value:string):null|HTMLElement {
var hashed = hash_key(value);
return hashed
? this.control.querySelector(`[data-value="${addSlashes(hashed)}"]`)
getItem(item:string|TomItem|null):null|TomItem {

if( typeof item == 'object' ){
return item;
}

var value = hash_key(item);
return value
? this.control.querySelector(`[data-value="${addSlashes(value)}"]`)
: null;
}

Expand Down Expand Up @@ -1852,43 +1857,38 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
* the provided value.
*
*/
removeItem( value?:string, silent?:boolean ){
var i, idx;

removeItem( item:string|TomItem|null=null, silent?:boolean ){
const self = this;
const hashed = hash_key(value);

if( !hashed ) return;

const item = self.getItem(hashed);
item = self.getItem(item);

if( !item ) return;

i = self.items.indexOf(hashed);

if (i !== -1) {
item.remove();
if( item.classList.contains('active') ){
idx = self.activeItems.indexOf(item);
self.activeItems.splice(idx, 1);
removeClasses(item,'active');
}
var i,idx;
const value = item.dataset.value;
i = nodeIndex(item);

self.items.splice(i, 1);
self.lastQuery = null;
if (!self.settings.persist && self.userOptions.hasOwnProperty(hashed)) {
self.removeOption(hashed, silent);
}
item.remove();
if( item.classList.contains('active') ){
idx = self.activeItems.indexOf(item);
self.activeItems.splice(idx, 1);
removeClasses(item,'active');
}

if (i < self.caretPos) {
self.setCaret(self.caretPos - 1);
}
self.items.splice(i, 1);
self.lastQuery = null;
if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {
self.removeOption(value, silent);
}

self.updateOriginalInput({silent: silent});
self.refreshState();
self.positionDropdown();
self.trigger('item_remove', hashed, item);
if (i < self.caretPos) {
self.setCaret(self.caretPos - 1);
}

self.updateOriginalInput({silent: silent});
self.refreshState();
self.positionDropdown();
self.trigger('item_remove', value, item);

}

/**
Expand Down Expand Up @@ -2222,15 +2222,15 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
*
*/
deleteSelection(e:KeyboardEvent):boolean {
var direction, selection, values, caret, tail;
var direction, selection, caret, tail;
var self = this;

direction = (e && e.keyCode === constants.KEY_BACKSPACE) ? -1 : 1;
selection = getSelection(self.control_input);


// determine items that will be removed
values = [];
const rm_items:TomItem[] = [];

if (self.activeItems.length) {

Expand All @@ -2240,17 +2240,21 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
if (direction > 0) { caret++; }

for( const item of self.activeItems ){
values.push( item.dataset.value );
rm_items.push( item );
}

} else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {
const items = self.controlChildren();
if (direction < 0 && selection.start === 0 && selection.length === 0) {
values.push(self.items[self.caretPos - 1]);
rm_items.push( items[self.caretPos - 1]);

} else if (direction > 0 && selection.start === self.inputValue().length) {
values.push(self.items[self.caretPos]);
rm_items.push(items[self.caretPos]);
}
}

const values = rm_items.map(item => item.dataset.value);

// allow the callback to abort
if (!values.length || (typeof self.settings.onDelete === 'function' && self.settings.onDelete.call(self,values,e) === false)) {
return false;
Expand All @@ -2262,8 +2266,9 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
if (typeof caret !== 'undefined') {
self.setCaret(caret);
}
while (values.length) {
self.removeItem(values.pop());

while( rm_items.length ){
self.removeItem(rm_items.pop());
}

self.showInput();
Expand Down Expand Up @@ -2386,8 +2391,8 @@ export default class TomSelect extends MicroPlugin(MicroEvent){
* Return list of item dom elements
*
*/
controlChildren():HTMLElement[]{
return Array.from( this.control.getElementsByClassName(this.settings.itemClass) ) as HTMLElement[];
controlChildren():TomItem[]{
return Array.from( this.control.getElementsByClassName(this.settings.itemClass) ) as TomItem[];
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ export type TomCreateFilter = (input:string) => boolean;
export type TomCreateCallback = (data?:TomOption)=>void;

export type TomCreate = (input:string,create:TomCreateCallback) => boolean;

export interface TomItem extends HTMLElement{
dataset:{
value: string;
}
}
19 changes: 12 additions & 7 deletions test/tests/config-duplicates.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ describe('duplicates', function() {

assert.equal(test.instance.items.length,3,'should have all three');

// remove
test.instance.removeItem('a');
assert.equal(test.instance.items.length,2,'should remove first');
test.instance.removeItem('a');
assert.equal(test.instance.items.length,1,'should remove second');
test.instance.removeItem('a');
assert.equal(0,test.instance.items.length,0,'should remove last');


// remove items in order
const items = test.instance.controlChildren();
await asyncClick(test.instance.control_input);

while( items.length ){
items.pop();
await asyncType('\b',test.instance.control_input);
const items_after = test.instance.controlChildren();
assert.deepEqual( items, items_after);
}
});


Expand Down

0 comments on commit 18c7fb0

Please sign in to comment.