carbon-components-angular
Version:
Next generation components
362 lines (359 loc) • 13.7 kB
JavaScript
/*!
*
* Neutrino v0.0.0 | dropdown-list.component.js
*
* Copyright 2014, 2018 IBM
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from "@angular/core";
import { AbstractDropdownView } from "./../abstract-dropdown-view.class";
import { watchFocusJump } from "./../dropdowntools";
/**
* ```html
* <ibm-dropdown-list [items]="listItems"></ibm-dropdown-list>
* ```
* ```typescript
* listItems = [
* {
* content: "item one",
* selected: false
* },
* {
* content: "item two",
* selected: false,
* },
* {
* content: "item three",
* selected: false
* },
* {
* content: "item four",
* selected: false
* }
* ];
* ```
*/
var DropdownList = /** @class */ (function () {
/**
* Creates an instance of `DropdownList`.
*/
function DropdownList(elementRef) {
this.elementRef = elementRef;
/**
* The list items belonging to the `DropdownList`.
*/
this.items = [];
/**
* Template to bind to items in the `DropdownList` (optional).
*/
this.listTpl = null;
/**
* Event to emit selection of a list item within the `DropdownList`.
*/
this.select = new EventEmitter();
/**
* Defines whether or not the `DropdownList` supports selecting multiple items as opposed to single
* item selection.
*/
this.type = "single";
/**
* Defines the rendering size of the `DropdownList` input component.
*/
this.size = "md";
/**
* Holds the list of items that will be displayed in the `DropdownList`.
* It differs from the the complete set of items when filtering is used (but
* it is always a subset of the total items in `DropdownList`).
*/
this.displayItems = [];
/**
* Maintains the index for the selected item within the `DropdownList`.
*/
this.index = -1;
}
/**
* Updates list when changes occur within the items belonging to the `DropdownList`.
*/
DropdownList.prototype.ngOnChanges = function (changes) {
if (changes.items) {
this.updateList(changes.items.currentValue);
}
};
/**
* Retrieves array of list items and index of the selected item after view has rendered.
* Additionally, any Observables for the `DropdownList` are initialized.
*/
DropdownList.prototype.ngAfterViewInit = function () {
this.listElementList = Array.from(this.list.nativeElement.querySelectorAll("li"));
this.index = this.items.findIndex(function (item) { return item.selected; });
this.setupFocusObservable();
};
/**
* Removes any Observables on destruction of the component.
*/
DropdownList.prototype.ngOnDestroy = function () {
if (this.focusJump) {
this.focusJump.unsubscribe();
}
};
/**
* Updates the displayed list of items and then retrieves the most current properties for the `DropdownList` from the DOM.
*/
DropdownList.prototype.updateList = function (items) {
var _this = this;
this.items = items.map(function (item) { return Object.assign({}, item); });
this.displayItems = this.items;
setTimeout(function () {
_this.listElementList = Array.from(_this.list.nativeElement.querySelectorAll("li"));
}, 0);
this.index = this.items.findIndex(function (item) { return item.selected; });
this.setupFocusObservable();
setTimeout(function () {
if (_this.type === "single") {
_this.select.emit({ item: _this.items.find(function (item) { return item.selected; }) });
}
else {
_this.select.emit(_this.getSelected() || []);
}
});
};
/**
* Filters the items being displayed in the DOM list.
*/
DropdownList.prototype.filterBy = function (query) {
if (query === void 0) { query = ""; }
if (query) {
this.displayItems = this.items.filter(function (item) { return item.content.toLowerCase().includes(query.toLowerCase()); });
}
else {
this.displayItems = this.items;
}
};
/**
* Initializes (or re-initializes) the Observable that handles switching focus to an element based on
* key input matching the first letter of the item in the list.
*/
DropdownList.prototype.setupFocusObservable = function () {
if (this.focusJump) {
this.focusJump.unsubscribe();
}
var elList = Array.from(this.list.nativeElement.querySelectorAll("li"));
this.focusJump = watchFocusJump(this.list.nativeElement, elList)
.subscribe(function (el) {
el.focus();
});
};
/**
* Returns the `ListItem` that is subsequent to the selected item in the `DropdownList`.
*/
DropdownList.prototype.getNextItem = function () {
if (this.index < this.items.length - 1) {
this.index++;
}
return this.items[this.index];
};
/**
* Returns `true` if the selected item is not the last item in the `DropdownList`.
*/
DropdownList.prototype.hasNextElement = function () {
if (this.index < this.items.length - 1) {
return true;
}
return false;
};
/**
* Returns the `HTMLElement` for the item that is subsequent to the selected item.
*/
DropdownList.prototype.getNextElement = function () {
if (this.index < this.items.length - 1) {
this.index++;
}
var elem = this.listElementList[this.index];
var item = this.items[this.index];
if (item.disabled) {
return this.getNextElement();
}
return elem;
};
/**
* Returns the `ListItem` that precedes the selected item within `DropdownList`.
*/
DropdownList.prototype.getPrevItem = function () {
if (this.index > 0) {
this.index--;
}
return this.items[this.index];
};
/**
* Returns `true` if the selected item is not the first in the list.
*/
DropdownList.prototype.hasPrevElement = function () {
if (this.index > 0) {
return true;
}
return false;
};
/**
* Returns the `HTMLElement` for the item that precedes the selected item.
*/
DropdownList.prototype.getPrevElement = function () {
if (this.index > 0) {
this.index--;
}
var elem = this.listElementList[this.index];
var item = this.items[this.index];
if (item.disabled) {
return this.getPrevElement();
}
return elem;
};
/**
* Returns the `ListItem` that is selected within `DropdownList`.
*/
DropdownList.prototype.getCurrentItem = function () {
if (this.index < 0) {
return this.items[0];
}
return this.items[this.index];
};
/**
* Returns the `HTMLElement` for the item that is selected within the `DropdownList`.
*/
DropdownList.prototype.getCurrentElement = function () {
if (this.index < 0) {
return this.listElementList[0];
}
return this.listElementList[this.index];
};
/**
* Returns a list containing the selected item(s) in the `DropdownList`.
*/
DropdownList.prototype.getSelected = function () {
var selected = this.items.filter(function (item) { return item.selected; });
if (selected.length === 0) {
return null;
}
return selected;
};
/**
* Transforms array input list of items to the correct state by updating the selected item(s).
*/
DropdownList.prototype.propagateSelected = function (value) {
for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
var newItem = value_1[_i];
// copy the item
var tempNewItem = Object.assign({}, newItem);
// deleted selected because it's what we _want_ to change
delete tempNewItem.selected;
// stringify for compare
tempNewItem = JSON.stringify(tempNewItem);
for (var _a = 0, _b = this.items; _a < _b.length; _a++) {
var oldItem = _b[_a];
var tempOldItem = Object.assign({}, oldItem);
delete tempOldItem.selected;
tempOldItem = JSON.stringify(tempOldItem);
// do the compare
if (tempOldItem.includes(tempNewItem)) {
// oldItem = Object.assign(oldItem, newItem);
oldItem.selected = newItem.selected;
}
else {
oldItem.selected = false;
}
}
}
};
/**
* Initalizes focus in the list, effectivly a wrapper for `getCurrentElement().focus()`
*/
DropdownList.prototype.initFocus = function () {
this.getCurrentElement().focus();
};
/**
* Manages the keyboard accessiblity for navigation and selection within a `DropdownList`.
*/
DropdownList.prototype.doKeyDown = function (event, item) {
if (event.key && (event.key === "Enter" || event.key === " ")) {
event.preventDefault();
this.doClick(event, item);
}
else if (event.key === "ArrowDown" || event.key === "ArrowUp") {
event.preventDefault();
// this.checkScrollArrows();
if (event.key === "ArrowDown" && this.hasNextElement()) {
this.getNextElement().focus();
}
else if (event.key === "ArrowUp") {
if (this.hasPrevElement()) {
this.getPrevElement().focus();
}
else if (this.getSelected()) {
this.clearSelected.nativeElement.focus();
}
}
if (event.shiftKey) {
event.target.click();
}
}
};
/**
* Emits the selected item or items after a mouse click event has occurred.
*/
DropdownList.prototype.doClick = function (event, item) {
if (!item.disabled) {
item.selected = !item.selected;
if (this.type === "single") {
// reset the selection
for (var _i = 0, _a = this.items; _i < _a.length; _i++) {
var otherItem = _a[_i];
if (item !== otherItem) {
otherItem.selected = false;
}
}
this.select.emit({ item: item });
}
else {
// emit an array of selected items
this.select.emit(this.getSelected());
}
this.index = this.items.indexOf(item);
}
};
DropdownList.decorators = [
{ type: Component, args: [{
selector: "ibm-dropdown-list",
template: "\n\t\t<ul\n\t\t\t#list\n\t\t\trole=\"listbox\"\n\t\t\tclass=\"bx--list-box__menu\">\n\t\t\t<li tabindex=\"{{item.disabled? -1 : 0}}\"\n\t\t\t\trole=\"option\"\n\t\t\t\t*ngFor=\"let item of displayItems\"\n\t\t\t\t(click)=\"doClick($event, item)\"\n\t\t\t\t(keydown)=\"doKeyDown($event, item)\"\n\t\t\t\tclass=\"bx--list-box__menu-item\"\n\t\t\t\t[ngClass]=\"{\n\t\t\t\t\tselected: item.selected,\n\t\t\t\t\tdisabled: item.disabled\n\t\t\t\t}\">\n\t\t\t\t<div\n\t\t\t\t\t*ngIf=\"!listTpl && type === 'multi'\"\n\t\t\t\t\tclass=\"bx--form-item bx--checkbox-wrapper\">\n\t\t\t\t\t<input\n\t\t\t\t\t\tclass=\"bx--checkbox\"\n\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t[checked]=\"item.selected\"\n\t\t\t\t\t\t[disabled]=\"item.disabled\"\n\t\t\t\t\t\t(click)=\"doClick($event, item)\"\n\t\t\t\t\t\ttabindex=\"-1\">\n\t\t\t\t\t<label class=\"bx--checkbox-label\">{{item.content}}</label>\n\t\t\t\t</div>\n\t\t\t\t<ng-container *ngIf=\"!listTpl && type === 'single'\">{{item.content}}</ng-container>\n\t\t\t\t<ng-template\n\t\t\t\t\t*ngIf=\"listTpl\"\n\t\t\t\t\t[ngTemplateOutletContext]=\"{item: item}\"\n\t\t\t\t\t[ngTemplateOutlet]=\"listTpl\">\n\t\t\t\t</ng-template>\n\t\t\t</li>\n\t\t</ul>",
providers: [
{
provide: AbstractDropdownView,
useExisting: DropdownList
}
]
},] },
];
/** @nocollapse */
DropdownList.ctorParameters = function () { return [
{ type: ElementRef }
]; };
DropdownList.propDecorators = {
items: [{ type: Input }],
listTpl: [{ type: Input }],
select: [{ type: Output }],
list: [{ type: ViewChild, args: ["list",] }],
clearSelected: [{ type: ViewChild, args: ["clearSelected",] }],
type: [{ type: Input }]
};
return DropdownList;
}());
export { DropdownList };
//# sourceMappingURL=dropdown-list.component.js.map