novo-elements
Version:
Bullhorn's NOVO Element Repository for Angular 2
283 lines • 12.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// NG2
var core_1 = require("@angular/core");
var forms_1 = require("@angular/forms");
// APP
var Overlay_1 = require("../overlay/Overlay");
var KeyCodes_1 = require("../../utils/key-codes/KeyCodes");
var novo_label_service_1 = require("../../services/novo-label-service");
var Helpers_1 = require("../../utils/Helpers");
// Value accessor for the component (supports ngModel)
var SELECT_VALUE_ACCESSOR = {
provide: forms_1.NG_VALUE_ACCESSOR,
useExisting: core_1.forwardRef(function () { return NovoSelectElement; }),
multi: true
};
var NovoSelectElement = (function () {
function NovoSelectElement(element, labels) {
this.element = element;
this.labels = labels;
this.placeholder = 'Select...';
this.onSelect = new core_1.EventEmitter();
this.selectedIndex = -1;
this.empty = true;
this.header = {
open: false,
valid: true,
value: ''
};
this.onModelChange = function () { };
this.onModelTouched = function () { };
this.filterTerm = '';
}
NovoSelectElement.prototype.ngOnInit = function () {
this.ngOnChanges();
};
NovoSelectElement.prototype.ngOnChanges = function (changes) {
var _this = this;
this.readonly = this.readonly === true;
if (this.options && this.options.length && typeof this.options[0] === 'string') {
this.filteredOptions = this.options.map(function (item) {
return { value: item, label: item };
});
}
else {
this.filteredOptions = this.options.filter(function (item) {
return !item.readOnly;
});
this.filteredOptions.forEach(function (element) {
element.active = false;
});
}
if (!this.model && !this.createdItem) {
this.clear();
}
else if (this.createdItem) {
var item = this.options.find(function (i) { return i.label === _this.createdItem; });
var index = this.options.indexOf(item);
this.select(item, index);
}
else {
this.writeValue(this.model);
}
if (this.panelOpen) {
this.openPanel();
}
};
/** BEGIN: Convienient Panel Methods. */
NovoSelectElement.prototype.openPanel = function () {
this.overlay.openPanel();
};
NovoSelectElement.prototype.closePanel = function () {
this.overlay.closePanel();
};
Object.defineProperty(NovoSelectElement.prototype, "panelOpen", {
get: function () {
return this.overlay && this.overlay.panelOpen;
},
enumerable: true,
configurable: true
});
/** END: Convienient Panel Methods. */
/**
* This method closes the panel, and if a value is specified, also sets the associated
* control to that value. It will also mark the control as dirty if this interaction
* stemmed from the user.
*/
NovoSelectElement.prototype.setValueAndClose = function (event) {
if (event.value && event.index >= 0) {
this.select(event.value, event.index);
}
this.closePanel();
};
NovoSelectElement.prototype.select = function (option, i, fireEvents) {
if (fireEvents === void 0) { fireEvents = true; }
if (this.selected) {
this.selected.active = false;
}
this.selectedIndex = i;
this.selected = option;
this.selected.active = true;
this.empty = false;
if (fireEvents) {
this.onModelChange(this.selected.value);
this.onSelect.emit({ selected: this.selected.value });
}
};
NovoSelectElement.prototype.clear = function () {
this.selected = {
label: this.placeholder,
value: null,
active: false
};
this.header = {
open: false,
valid: true,
value: ''
};
this.selectedIndex = -1;
this.empty = true;
};
NovoSelectElement.prototype.onKeyDown = function (event) {
var _this = this;
if (this.panelOpen) {
if (!this.header.open) {
// Prevent Scrolling
event.preventDefault();
}
// Close popup on escape key
if (event.keyCode === KeyCodes_1.KeyCodes.ESC) {
this.closePanel();
return;
}
if (event.keyCode === KeyCodes_1.KeyCodes.ENTER) {
if (this.header.open && this.header.value) {
this.saveHeader();
return;
}
this.setValueAndClose({ value: this.filteredOptions[this.selectedIndex], index: this.selectedIndex });
return;
}
if (event.keyCode === KeyCodes_1.KeyCodes.UP && this.selectedIndex > 0) {
this.selectedIndex--;
this.select(this.filteredOptions[this.selectedIndex], this.selectedIndex);
this.scrollToSelected();
}
else if (event.keyCode === KeyCodes_1.KeyCodes.DOWN && this.selectedIndex < this.filteredOptions.length - 1) {
this.selectedIndex++;
this.select(this.filteredOptions[this.selectedIndex], this.selectedIndex);
this.scrollToSelected();
if (this.header.open) {
this.toggleHeader(null, false);
}
}
else if (event.keyCode === KeyCodes_1.KeyCodes.UP && this.selectedIndex === 0) {
this.selectedIndex--;
this.toggleHeader(null, true);
}
else if (event.keyCode >= 65 && event.keyCode <= 90 || event.keyCode === KeyCodes_1.KeyCodes.SPACE) {
clearTimeout(this.filterTermTimeout);
this.filterTermTimeout = setTimeout(function () { _this.filterTerm = ''; }, 2000);
var char = String.fromCharCode(event.keyCode);
this.filterTerm = this.filterTerm.concat(char);
// let element = this.element.nativeElement;
// let list = element.querySelector('.novo-select-list');
// let item = element.querySelector(`[data-automation-value^="${this.filterTerm}" i]`);
var item = this.filteredOptions.find(function (i) { return i.label.toUpperCase().indexOf(_this.filterTerm) === 0; });
if (item) {
this.select(item, this.filteredOptions.indexOf(item));
this.scrollToSelected();
}
}
else if ([KeyCodes_1.KeyCodes.BACKSPACE, KeyCodes_1.KeyCodes.DELETE].includes(event.keyCode)) {
clearTimeout(this.filterTermTimeout);
this.filterTermTimeout = setTimeout(function () { _this.filterTerm = ''; }, 2000);
this.filterTerm = this.filterTerm.slice(0, -1);
}
}
else {
if ([KeyCodes_1.KeyCodes.DOWN, KeyCodes_1.KeyCodes.UP].includes(event.keyCode)) {
this.panelOpen ? this.closePanel() : this.openPanel();
}
}
};
NovoSelectElement.prototype.scrollToSelected = function () {
this.scrollToIndex(this.selectedIndex);
};
NovoSelectElement.prototype.scrollToIndex = function (index) {
var element = this.overlay._overlayRef.overlayElement;
var list = element.querySelector('.novo-select-list');
var items = list.querySelectorAll('li');
var item = items[this.headerConfig ? index + 1 : index];
if (item) {
list.scrollTop = item.offsetTop;
}
};
NovoSelectElement.prototype.toggleHeader = function (event, forceValue) {
if (event) {
event.stopPropagation();
event.preventDefault();
}
// Reverse the active property (if forceValue, use that)
this.header = {
open: forceValue !== undefined ? forceValue : !this.header.open,
value: '',
valid: true
};
};
NovoSelectElement.prototype.highlight = function (match, query) {
// Replaces the capture string with a the same string inside of a "strong" tag
return query ? match.replace(new RegExp(this.escapeRegexp(query), 'gi'), '<strong>$&</strong>') : match;
};
NovoSelectElement.prototype.escapeRegexp = function (queryToEscape) {
// Ex: if the capture is "a" the result will be \a
return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
};
NovoSelectElement.prototype.saveHeader = function () {
if (this.header.value) {
this.headerConfig.onSave(this.header.value);
this.createdItem = this.header.value;
this.closePanel();
}
else {
this.header.valid = false;
}
};
NovoSelectElement.prototype.writeValue = function (model) {
this.model = model;
if (this.options) {
var item = this.filteredOptions.find(function (i) { return i.value === model; });
if (!item && !Helpers_1.Helpers.isEmpty(model)) {
item = {
label: model,
value: model
};
if (!item.readOnly) {
this.options.unshift(item);
}
}
if (item) {
this.select(item, this.filteredOptions.indexOf(item));
this.empty = false;
}
else {
this.clear();
}
}
};
NovoSelectElement.prototype.registerOnChange = function (fn) {
this.onModelChange = fn;
};
NovoSelectElement.prototype.registerOnTouched = function (fn) {
this.onModelTouched = fn;
};
return NovoSelectElement;
}());
NovoSelectElement.decorators = [
{ type: core_1.Component, args: [{
selector: 'novo-select',
providers: [SELECT_VALUE_ACCESSOR],
template: "\n <div (click)=\"openPanel()\" tabIndex=\"0\" type=\"button\" [class.empty]=\"empty\">{{selected.label}}<i class=\"bhi-collapse\"></i></div>\n <novo-overlay-template [parent]=\"element\" position=\"center\">\n <ul class=\"novo-select-list\" tabIndex=\"-1\" [class.header]=\"headerConfig\" [class.active]=\"panelOpen\">\n <ng-content></ng-content>\n <li *ngIf=\"headerConfig\" class=\"select-header\" [class.open]=\"header.open\">\n <button *ngIf=\"!header.open\" (click)=\"toggleHeader($event); false\" tabIndex=\"-1\" type=\"button\" class=\"header\"><i class=\"bhi-add-thin\"></i> {{headerConfig.label}}</button>\n <div *ngIf=\"header.open\" [ngClass]=\"{active: header.open}\">\n <input autofocus type=\"text\" [placeholder]=\"headerConfig.placeholder\" [attr.id]=\"name\" autocomplete=\"false\" [(ngModel)]=\"header.value\" [ngClass]=\"{invalid: !header.valid}\"/>\n <footer>\n <button (click)=\"toggleHeader($event, false)\">{{labels.cancel}}</button>\n <button (click)=\"saveHeader()\" class=\"primary\">{{labels.save}}</button>\n </footer>\n </div>\n </li>\n <li *ngFor=\"let option of filteredOptions; let i = index\" [ngClass]=\"{active: option.active}\" (click)=\"setValueAndClose({value: option, index: i})\" [attr.data-automation-value]=\"option.label\">\n <span [innerHtml]=\"highlight(option.label, filterTerm)\"></span>\n <i *ngIf=\"option.active\" class=\"bhi-check\"></i>\n </li>\n </ul>\n </novo-overlay-template>\n ",
host: {
'(keydown)': 'onKeyDown($event)'
}
},] },
];
/** @nocollapse */
NovoSelectElement.ctorParameters = function () { return [
{ type: core_1.ElementRef, },
{ type: novo_label_service_1.NovoLabelService, },
]; };
NovoSelectElement.propDecorators = {
'name': [{ type: core_1.Input },],
'options': [{ type: core_1.Input },],
'placeholder': [{ type: core_1.Input },],
'readonly': [{ type: core_1.Input },],
'headerConfig': [{ type: core_1.Input },],
'onSelect': [{ type: core_1.Output },],
'overlay': [{ type: core_1.ViewChild, args: [Overlay_1.NovoOverlayTemplate,] },],
'onKeyDown': [{ type: core_1.HostListener, args: ['keydown', ['$event'],] },],
};
exports.NovoSelectElement = NovoSelectElement;
//# sourceMappingURL=Select.js.map