UNPKG

17.4 kBJavaScriptView Raw
1import { forwardRef, EventEmitter, Component, ChangeDetectionStrategy, ViewEncapsulation, ElementRef, ChangeDetectorRef, Input, Output, ViewChild, ContentChild, ContentChildren, NgModule } from '@angular/core';
2import { CommonModule } from '@angular/common';
3import { Header, Footer, PrimeTemplate, SharedModule } from 'primeng/api';
4import { DomHandler } from 'primeng/dom';
5import { ObjectUtils, FilterUtils } from 'primeng/utils';
6import { NG_VALUE_ACCESSOR } from '@angular/forms';
7import { RippleModule } from 'primeng/ripple';
8
9const LISTBOX_VALUE_ACCESSOR = {
10 provide: NG_VALUE_ACCESSOR,
11 useExisting: forwardRef(() => Listbox),
12 multi: true
13};
14class Listbox {
15 constructor(el, cd) {
16 this.el = el;
17 this.cd = cd;
18 this.checkbox = false;
19 this.filter = false;
20 this.filterMode = 'contains';
21 this.metaKeySelection = true;
22 this.showToggleAll = true;
23 this.onChange = new EventEmitter();
24 this.onClick = new EventEmitter();
25 this.onDblClick = new EventEmitter();
26 this.onModelChange = () => { };
27 this.onModelTouched = () => { };
28 this.disabledSelectedOptions = [];
29 }
30 get options() {
31 return this._options;
32 }
33 set options(val) {
34 let opts = this.optionLabel ? ObjectUtils.generateSelectItems(val, this.optionLabel) : val;
35 this._options = opts;
36 }
37 get filterValue() {
38 return this._filterValue;
39 }
40 set filterValue(val) {
41 this._filterValue = val;
42 }
43 ngAfterContentInit() {
44 this.templates.forEach((item) => {
45 switch (item.getType()) {
46 case 'item':
47 this.itemTemplate = item.template;
48 break;
49 case 'header':
50 this.headerTemplate = item.template;
51 break;
52 case 'footer':
53 this.footerTemplate = item.template;
54 break;
55 default:
56 this.itemTemplate = item.template;
57 break;
58 }
59 });
60 }
61 writeValue(value) {
62 this.value = value;
63 this.setDisabledSelectedOptions();
64 this.cd.markForCheck();
65 }
66 registerOnChange(fn) {
67 this.onModelChange = fn;
68 }
69 registerOnTouched(fn) {
70 this.onModelTouched = fn;
71 }
72 setDisabledState(val) {
73 this.disabled = val;
74 this.cd.markForCheck();
75 }
76 onOptionClick(event, option) {
77 if (this.disabled || option.disabled || this.readonly) {
78 return;
79 }
80 if (this.multiple) {
81 if (this.checkbox)
82 this.onOptionClickCheckbox(event, option);
83 else
84 this.onOptionClickMultiple(event, option);
85 }
86 else {
87 this.onOptionClickSingle(event, option);
88 }
89 this.onClick.emit({
90 originalEvent: event,
91 option: option,
92 value: this.value
93 });
94 this.optionTouched = false;
95 }
96 onOptionTouchEnd(event, option) {
97 if (this.disabled || option.disabled || this.readonly) {
98 return;
99 }
100 this.optionTouched = true;
101 }
102 onOptionDoubleClick(event, option) {
103 if (this.disabled || option.disabled || this.readonly) {
104 return;
105 }
106 this.onDblClick.emit({
107 originalEvent: event,
108 option: option,
109 value: this.value
110 });
111 }
112 onOptionClickSingle(event, option) {
113 let selected = this.isSelected(option);
114 let valueChanged = false;
115 let metaSelection = this.optionTouched ? false : this.metaKeySelection;
116 if (metaSelection) {
117 let metaKey = (event.metaKey || event.ctrlKey);
118 if (selected) {
119 if (metaKey) {
120 this.value = null;
121 valueChanged = true;
122 }
123 }
124 else {
125 this.value = option.value;
126 valueChanged = true;
127 }
128 }
129 else {
130 this.value = selected ? null : option.value;
131 valueChanged = true;
132 }
133 if (valueChanged) {
134 this.onModelChange(this.value);
135 this.onChange.emit({
136 originalEvent: event,
137 value: this.value
138 });
139 }
140 }
141 onOptionClickMultiple(event, option) {
142 let selected = this.isSelected(option);
143 let valueChanged = false;
144 let metaSelection = this.optionTouched ? false : this.metaKeySelection;
145 if (metaSelection) {
146 let metaKey = (event.metaKey || event.ctrlKey);
147 if (selected) {
148 if (metaKey) {
149 this.removeOption(option);
150 }
151 else {
152 this.value = [option.value];
153 }
154 valueChanged = true;
155 }
156 else {
157 this.value = (metaKey) ? this.value || [] : [];
158 this.value = [...this.value, option.value];
159 valueChanged = true;
160 }
161 }
162 else {
163 if (selected) {
164 this.removeOption(option);
165 }
166 else {
167 this.value = [...this.value || [], option.value];
168 }
169 valueChanged = true;
170 }
171 if (valueChanged) {
172 this.onModelChange(this.value);
173 this.onChange.emit({
174 originalEvent: event,
175 value: this.value
176 });
177 }
178 }
179 onOptionClickCheckbox(event, option) {
180 if (this.disabled || this.readonly) {
181 return;
182 }
183 let selected = this.isSelected(option);
184 if (selected) {
185 this.removeOption(option);
186 }
187 else {
188 this.value = this.value ? this.value : [];
189 this.value = [...this.value, option.value];
190 }
191 this.onModelChange(this.value);
192 this.onChange.emit({
193 originalEvent: event,
194 value: this.value
195 });
196 }
197 removeOption(option) {
198 this.value = this.value.filter(val => !ObjectUtils.equals(val, option.value, this.dataKey));
199 }
200 isSelected(option) {
201 let selected = false;
202 if (this.multiple) {
203 if (this.value) {
204 for (let val of this.value) {
205 if (ObjectUtils.equals(val, option.value, this.dataKey)) {
206 selected = true;
207 break;
208 }
209 }
210 }
211 }
212 else {
213 selected = ObjectUtils.equals(this.value, option.value, this.dataKey);
214 }
215 return selected;
216 }
217 get allChecked() {
218 if (this.filterValue) {
219 return this.allFilteredSelected();
220 }
221 else {
222 let optionCount = this.getEnabledOptionCount();
223 let disabledSelectedOptionCount = this.disabledSelectedOptions.length;
224 return this.value && this.options && (this.value.length > 0 && this.value.length == optionCount + disabledSelectedOptionCount);
225 }
226 }
227 getEnabledOptionCount() {
228 if (this.options) {
229 let count = 0;
230 for (let opt of this.options) {
231 if (!opt.disabled) {
232 count++;
233 }
234 }
235 return count;
236 }
237 else {
238 return 0;
239 }
240 }
241 allFilteredSelected() {
242 let allSelected;
243 let options = this.filterValue ? this.getFilteredOptions() : this.options;
244 if (this.value && options && options.length) {
245 allSelected = true;
246 for (let opt of this.options) {
247 if (this.isItemVisible(opt)) {
248 if (!this.isSelected(opt)) {
249 allSelected = false;
250 break;
251 }
252 }
253 }
254 }
255 return allSelected;
256 }
257 onFilter(event) {
258 this._filterValue = event.target.value;
259 }
260 toggleAll(event) {
261 if (this.disabled || this.readonly || !this.options || this.options.length === 0) {
262 return;
263 }
264 if (this.allChecked) {
265 if (this.disabledSelectedOptions && this.disabledSelectedOptions.length > 0) {
266 let value = [];
267 value = [...this.disabledSelectedOptions];
268 this.value = value;
269 }
270 else {
271 this.value = [];
272 }
273 }
274 else {
275 if (this.options) {
276 this.value = [];
277 if (this.disabledSelectedOptions && this.disabledSelectedOptions.length > 0) {
278 this.value = [...this.disabledSelectedOptions];
279 }
280 for (let i = 0; i < this.options.length; i++) {
281 let opt = this.options[i];
282 if (this.isItemVisible(opt) && !opt.disabled) {
283 this.value.push(opt.value);
284 }
285 }
286 }
287 }
288 this.onModelChange(this.value);
289 this.onChange.emit({ originalEvent: event, value: this.value });
290 event.preventDefault();
291 }
292 isItemVisible(option) {
293 if (this.filterValue) {
294 let visible;
295 if (this.filterMode) {
296 visible = FilterUtils[this.filterMode](option.label, this.filterValue, this.filterLocale);
297 }
298 else {
299 visible = true;
300 }
301 return visible;
302 }
303 else {
304 return true;
305 }
306 }
307 onOptionKeyDown(event, option) {
308 if (this.readonly) {
309 return;
310 }
311 let item = event.currentTarget;
312 switch (event.which) {
313 //down
314 case 40:
315 var nextItem = this.findNextItem(item);
316 if (nextItem) {
317 nextItem.focus();
318 }
319 event.preventDefault();
320 break;
321 //up
322 case 38:
323 var prevItem = this.findPrevItem(item);
324 if (prevItem) {
325 prevItem.focus();
326 }
327 event.preventDefault();
328 break;
329 //enter
330 case 13:
331 this.onOptionClick(event, option);
332 event.preventDefault();
333 break;
334 }
335 }
336 findNextItem(item) {
337 let nextItem = item.nextElementSibling;
338 if (nextItem)
339 return DomHandler.hasClass(nextItem, 'p-disabled') || DomHandler.isHidden(nextItem) ? this.findNextItem(nextItem) : nextItem;
340 else
341 return null;
342 }
343 findPrevItem(item) {
344 let prevItem = item.previousElementSibling;
345 if (prevItem)
346 return DomHandler.hasClass(prevItem, 'p-disabled') || DomHandler.isHidden(prevItem) ? this.findPrevItem(prevItem) : prevItem;
347 else
348 return null;
349 }
350 getFilteredOptions() {
351 let filteredOptions = [];
352 if (this.filterValue) {
353 for (let i = 0; i < this.options.length; i++) {
354 let opt = this.options[i];
355 if (this.isItemVisible(opt) && !opt.disabled) {
356 filteredOptions.push(opt);
357 }
358 }
359 return filteredOptions;
360 }
361 else {
362 return this.options;
363 }
364 }
365 onHeaderCheckboxFocus() {
366 this.headerCheckboxFocus = true;
367 }
368 onHeaderCheckboxBlur() {
369 this.headerCheckboxFocus = false;
370 }
371 setDisabledSelectedOptions() {
372 if (this.options) {
373 this.disabledSelectedOptions = [];
374 if (this.value) {
375 for (let opt of this.options) {
376 if (opt.disabled && this.isSelected(opt)) {
377 this.disabledSelectedOptions.push(opt.value);
378 }
379 }
380 }
381 }
382 }
383}
384Listbox.decorators = [
385 { type: Component, args: [{
386 selector: 'p-listbox',
387 template: `
388 <div [ngClass]="'p-listbox p-component'" [ngStyle]="style" [class]="styleClass">
389 <div class="p-listbox-header" *ngIf="headerFacet || headerTemplate">
390 <ng-content select="p-header"></ng-content>
391 <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
392 </div>
393 <div class="p-listbox-header" *ngIf="(checkbox && multiple && showToggleAll) || filter">
394 <div class="p-checkbox p-component" *ngIf="checkbox && multiple && showToggleAll">
395 <div class="p-hidden-accessible">
396 <input type="checkbox" readonly="readonly" [checked]="allChecked" (focus)="onHeaderCheckboxFocus()" (blur)="onHeaderCheckboxBlur()" (keydown.space)="toggleAll($event)">
397 </div>
398 <div #headerchkbox class="p-checkbox-box" [ngClass]="{'p-highlight': allChecked, 'p-focus': headerCheckboxFocus}" (click)="toggleAll($event)">
399 <span class="p-checkbox-icon" [ngClass]="{'pi pi-check':allChecked}"></span>
400 </div>
401 </div>
402 <div class="p-listbox-filter-container" *ngIf="filter">
403 <input type="text" [value]="filterValue||''" (input)="onFilter($event)" class="p-listbox-filter p-inputtext p-component" [disabled]="disabled" [attr.placeholder]="filterPlaceHolder" [attr.aria-label]="ariaFilterLabel">
404 <span class="p-listbox-filter-icon pi pi-search"></span>
405 </div>
406 </div>
407 <div [ngClass]="'p-listbox-list-wrapper'" [ngStyle]="listStyle" [class]="listStyleClass">
408 <ul class="p-listbox-list" role="listbox" aria-multiselectable="multiple">
409 <li *ngFor="let option of options; let i = index;" [style.display]="isItemVisible(option) ? 'flex' : 'none'" [attr.tabindex]="option.disabled ? null : '0'" pRipple
410 [ngClass]="{'p-listbox-item':true,'p-highlight':isSelected(option), 'p-disabled': option.disabled}" role="option" [attr.aria-label]="option.label"
411 [attr.aria-selected]="isSelected(option)" (click)="onOptionClick($event,option)" (dblclick)="onOptionDoubleClick($event,option)" (touchend)="onOptionTouchEnd($event,option)" (keydown)="onOptionKeyDown($event,option)">
412 <div class="p-checkbox p-component" *ngIf="checkbox && multiple">
413 <div class="p-checkbox-box" [ngClass]="{'p-highlight':isSelected(option)}">
414 <span class="p-checkbox-icon" [ngClass]="{'pi pi-check':isSelected(option)}"></span>
415 </div>
416 </div>
417 <span *ngIf="!itemTemplate">{{option.label}}</span>
418 <ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: option, index: i}"></ng-container>
419 </li>
420 </ul>
421 </div>
422 <div class="p-listbox-footer" *ngIf="footerFacet || footerTemplate">
423 <ng-content select="p-footer"></ng-content>
424 <ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
425 </div>
426 </div>
427 `,
428 providers: [LISTBOX_VALUE_ACCESSOR],
429 changeDetection: ChangeDetectionStrategy.OnPush,
430 encapsulation: ViewEncapsulation.None,
431 styles: [".p-listbox-list-wrapper{overflow:auto}.p-listbox-list{list-style-type:none;margin:0;padding:0}.p-listbox-item{cursor:pointer;overflow:hidden;position:relative}.p-listbox-header,.p-listbox-item{-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.p-listbox-filter-container{-ms-flex:1 1 auto;flex:1 1 auto;position:relative}.p-listbox-filter-icon{margin-top:-.5rem;position:absolute;top:50%}.p-listbox-filter{width:100%}"]
432 },] }
433];
434Listbox.ctorParameters = () => [
435 { type: ElementRef },
436 { type: ChangeDetectorRef }
437];
438Listbox.propDecorators = {
439 multiple: [{ type: Input }],
440 style: [{ type: Input }],
441 styleClass: [{ type: Input }],
442 listStyle: [{ type: Input }],
443 listStyleClass: [{ type: Input }],
444 readonly: [{ type: Input }],
445 disabled: [{ type: Input }],
446 checkbox: [{ type: Input }],
447 filter: [{ type: Input }],
448 filterMode: [{ type: Input }],
449 filterLocale: [{ type: Input }],
450 metaKeySelection: [{ type: Input }],
451 dataKey: [{ type: Input }],
452 showToggleAll: [{ type: Input }],
453 optionLabel: [{ type: Input }],
454 ariaFilterLabel: [{ type: Input }],
455 filterPlaceHolder: [{ type: Input }],
456 onChange: [{ type: Output }],
457 onClick: [{ type: Output }],
458 onDblClick: [{ type: Output }],
459 headerCheckboxViewChild: [{ type: ViewChild, args: ['headerchkbox',] }],
460 headerFacet: [{ type: ContentChild, args: [Header,] }],
461 footerFacet: [{ type: ContentChild, args: [Footer,] }],
462 templates: [{ type: ContentChildren, args: [PrimeTemplate,] }],
463 options: [{ type: Input }],
464 filterValue: [{ type: Input }]
465};
466class ListboxModule {
467}
468ListboxModule.decorators = [
469 { type: NgModule, args: [{
470 imports: [CommonModule, SharedModule, RippleModule],
471 exports: [Listbox, SharedModule],
472 declarations: [Listbox]
473 },] }
474];
475
476/**
477 * Generated bundle index. Do not edit.
478 */
479
480export { LISTBOX_VALUE_ACCESSOR, Listbox, ListboxModule };
481//# sourceMappingURL=primeng-listbox.js.map