mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
Apply Prettier (#581)
This commit is contained in:
@@ -1,28 +1,23 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
Input,
|
||||
Renderer2,
|
||||
} from '@angular/core';
|
||||
import { Directive, ElementRef, Input, Renderer2 } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: '[appA11yTitle]',
|
||||
selector: "[appA11yTitle]",
|
||||
})
|
||||
export class A11yTitleDirective {
|
||||
@Input() set appA11yTitle(title: string) {
|
||||
this.title = title;
|
||||
@Input() set appA11yTitle(title: string) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
private title: string;
|
||||
|
||||
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.el.nativeElement.hasAttribute("title")) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "title", this.title);
|
||||
}
|
||||
|
||||
private title: string;
|
||||
|
||||
constructor(private el: ElementRef, private renderer: Renderer2) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.el.nativeElement.hasAttribute('title')) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, 'title', this.title);
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute('aria-label')) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, 'aria-label', this.title);
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute("aria-label")) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "aria-label", this.title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,46 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
Input,
|
||||
OnChanges,
|
||||
} from '@angular/core';
|
||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
||||
import { Directive, ElementRef, Input, OnChanges } from "@angular/core";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
|
||||
import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
|
||||
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
|
||||
|
||||
import { ValidationService } from '../services/validation.service';
|
||||
import { ValidationService } from "../services/validation.service";
|
||||
|
||||
@Directive({
|
||||
selector: '[appApiAction]',
|
||||
selector: "[appApiAction]",
|
||||
})
|
||||
export class ApiActionDirective implements OnChanges {
|
||||
@Input() appApiAction: Promise<any>;
|
||||
@Input() appApiAction: Promise<any>;
|
||||
|
||||
constructor(private el: ElementRef, private validationService: ValidationService,
|
||||
private logService: LogService) { }
|
||||
constructor(
|
||||
private el: ElementRef,
|
||||
private validationService: ValidationService,
|
||||
private logService: LogService
|
||||
) {}
|
||||
|
||||
ngOnChanges(changes: any) {
|
||||
if (this.appApiAction == null || this.appApiAction.then == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.el.nativeElement.loading = true;
|
||||
|
||||
this.appApiAction.then((response: any) => {
|
||||
this.el.nativeElement.loading = false;
|
||||
}, (e: any) => {
|
||||
this.el.nativeElement.loading = false;
|
||||
|
||||
if ((e instanceof ErrorResponse || e.constructor.name === 'ErrorResponse') && (e as ErrorResponse).captchaRequired) {
|
||||
this.logService.error('Captcha required error response: ' + e.getSingleMessage());
|
||||
return;
|
||||
}
|
||||
this.logService?.error(`Received API exception: ${e}`);
|
||||
this.validationService.showError(e);
|
||||
});
|
||||
ngOnChanges(changes: any) {
|
||||
if (this.appApiAction == null || this.appApiAction.then == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.el.nativeElement.loading = true;
|
||||
|
||||
this.appApiAction.then(
|
||||
(response: any) => {
|
||||
this.el.nativeElement.loading = false;
|
||||
},
|
||||
(e: any) => {
|
||||
this.el.nativeElement.loading = false;
|
||||
|
||||
if (
|
||||
(e instanceof ErrorResponse || e.constructor.name === "ErrorResponse") &&
|
||||
(e as ErrorResponse).captchaRequired
|
||||
) {
|
||||
this.logService.error("Captcha required error response: " + e.getSingleMessage());
|
||||
return;
|
||||
}
|
||||
this.logService?.error(`Received API exception: ${e}`);
|
||||
this.validationService.showError(e);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,28 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
Input,
|
||||
NgZone,
|
||||
} from '@angular/core';
|
||||
import { Directive, ElementRef, Input, NgZone } from "@angular/core";
|
||||
|
||||
import { take } from 'rxjs/operators';
|
||||
import { take } from "rxjs/operators";
|
||||
|
||||
import { Utils } from 'jslib-common/misc/utils';
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
|
||||
@Directive({
|
||||
selector: '[appAutofocus]',
|
||||
selector: "[appAutofocus]",
|
||||
})
|
||||
export class AutofocusDirective {
|
||||
@Input() set appAutofocus(condition: boolean | string) {
|
||||
this.autofocus = condition === '' || condition === true;
|
||||
}
|
||||
|
||||
private autofocus: boolean;
|
||||
|
||||
constructor(private el: ElementRef, private ngZone: NgZone) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (!Utils.isMobileBrowser && this.autofocus) {
|
||||
if (this.ngZone.isStable) {
|
||||
this.el.nativeElement.focus();
|
||||
} else {
|
||||
this.ngZone.onStable.pipe(take(1)).subscribe(() => this.el.nativeElement.focus());
|
||||
}
|
||||
}
|
||||
@Input() set appAutofocus(condition: boolean | string) {
|
||||
this.autofocus = condition === "" || condition === true;
|
||||
}
|
||||
|
||||
private autofocus: boolean;
|
||||
|
||||
constructor(private el: ElementRef, private ngZone: NgZone) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (!Utils.isMobileBrowser && this.autofocus) {
|
||||
if (this.ngZone.isStable) {
|
||||
this.el.nativeElement.focus();
|
||||
} else {
|
||||
this.ngZone.onStable.pipe(take(1)).subscribe(() => this.el.nativeElement.focus());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
} from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: '[appBlurClick]',
|
||||
selector: "[appBlurClick]",
|
||||
})
|
||||
export class BlurClickDirective {
|
||||
constructor(private el: ElementRef) {
|
||||
}
|
||||
constructor(private el: ElementRef) {}
|
||||
|
||||
@HostListener('click') onClick() {
|
||||
this.el.nativeElement.blur();
|
||||
}
|
||||
@HostListener("click") onClick() {
|
||||
this.el.nativeElement.blur();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +1,59 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, OnInit } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: '[appBoxRow]',
|
||||
selector: "[appBoxRow]",
|
||||
})
|
||||
export class BoxRowDirective implements OnInit {
|
||||
el: HTMLElement = null;
|
||||
formEls: Element[];
|
||||
el: HTMLElement = null;
|
||||
formEls: Element[];
|
||||
|
||||
constructor(private elRef: ElementRef) {
|
||||
this.el = elRef.nativeElement;
|
||||
constructor(private elRef: ElementRef) {
|
||||
this.el = elRef.nativeElement;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.formEls = Array.from(
|
||||
this.el.querySelectorAll('input:not([type="hidden"]), select, textarea')
|
||||
);
|
||||
this.formEls.forEach((formEl) => {
|
||||
formEl.addEventListener(
|
||||
"focus",
|
||||
(event: Event) => {
|
||||
this.el.classList.add("active");
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
formEl.addEventListener(
|
||||
"blur",
|
||||
(event: Event) => {
|
||||
this.el.classList.remove("active");
|
||||
},
|
||||
false
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener("click", ["$event"]) onClick(event: Event) {
|
||||
const target = event.target as HTMLElement;
|
||||
if (
|
||||
target !== this.el &&
|
||||
!target.classList.contains("progress") &&
|
||||
!target.classList.contains("progress-bar")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.formEls = Array.from(this.el.querySelectorAll('input:not([type="hidden"]), select, textarea'));
|
||||
this.formEls.forEach(formEl => {
|
||||
formEl.addEventListener('focus', (event: Event) => {
|
||||
this.el.classList.add('active');
|
||||
}, false);
|
||||
|
||||
formEl.addEventListener('blur', (event: Event) => {
|
||||
this.el.classList.remove('active');
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener('click', ['$event']) onClick(event: Event) {
|
||||
const target = event.target as HTMLElement;
|
||||
if (target !== this.el && !target.classList.contains('progress') &&
|
||||
!target.classList.contains('progress-bar')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.formEls.length > 0) {
|
||||
const formEl = (this.formEls[0] as HTMLElement);
|
||||
if (formEl.tagName.toLowerCase() === 'input') {
|
||||
const inputEl = (formEl as HTMLInputElement);
|
||||
if (inputEl.type != null && inputEl.type.toLowerCase() === 'checkbox') {
|
||||
inputEl.click();
|
||||
return;
|
||||
}
|
||||
}
|
||||
formEl.focus();
|
||||
if (this.formEls.length > 0) {
|
||||
const formEl = this.formEls[0] as HTMLElement;
|
||||
if (formEl.tagName.toLowerCase() === "input") {
|
||||
const inputEl = formEl as HTMLInputElement;
|
||||
if (inputEl.type != null && inputEl.type.toLowerCase() === "checkbox") {
|
||||
inputEl.click();
|
||||
return;
|
||||
}
|
||||
}
|
||||
formEl.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,76 @@
|
||||
import {
|
||||
CdkFixedSizeVirtualScroll,
|
||||
FixedSizeVirtualScrollStrategy,
|
||||
VIRTUAL_SCROLL_STRATEGY,
|
||||
} from '@angular/cdk/scrolling';
|
||||
import {
|
||||
Directive,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
CdkFixedSizeVirtualScroll,
|
||||
FixedSizeVirtualScrollStrategy,
|
||||
VIRTUAL_SCROLL_STRATEGY,
|
||||
} from "@angular/cdk/scrolling";
|
||||
import { Directive, forwardRef } from "@angular/core";
|
||||
|
||||
// Custom virtual scroll strategy for cdk-virtual-scroll
|
||||
// Uses a sample list item to set the itemSize for FixedSizeVirtualScrollStrategy
|
||||
// The use case is the same as FixedSizeVirtualScrollStrategy, but it avoids locking in pixel sizes in the template.
|
||||
export class CipherListVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
|
||||
private checkItemSizeCallback: any;
|
||||
private timeout: any;
|
||||
private checkItemSizeCallback: any;
|
||||
private timeout: any;
|
||||
|
||||
constructor(itemSize: number, minBufferPx: number, maxBufferPx: number, checkItemSizeCallback: any) {
|
||||
super(itemSize, minBufferPx, maxBufferPx);
|
||||
this.checkItemSizeCallback = checkItemSizeCallback;
|
||||
constructor(
|
||||
itemSize: number,
|
||||
minBufferPx: number,
|
||||
maxBufferPx: number,
|
||||
checkItemSizeCallback: any
|
||||
) {
|
||||
super(itemSize, minBufferPx, maxBufferPx);
|
||||
this.checkItemSizeCallback = checkItemSizeCallback;
|
||||
}
|
||||
|
||||
onContentRendered() {
|
||||
if (this.timeout != null) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
|
||||
onContentRendered() {
|
||||
if (this.timeout != null) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
|
||||
this.timeout = setTimeout(this.checkItemSizeCallback, 500);
|
||||
}
|
||||
this.timeout = setTimeout(this.checkItemSizeCallback, 500);
|
||||
}
|
||||
}
|
||||
|
||||
export function _cipherListVirtualScrollStrategyFactory(cipherListDir: CipherListVirtualScroll) {
|
||||
return cipherListDir._scrollStrategy;
|
||||
return cipherListDir._scrollStrategy;
|
||||
}
|
||||
|
||||
@Directive({
|
||||
selector: 'cdk-virtual-scroll-viewport[itemSize]',
|
||||
providers: [{
|
||||
provide: VIRTUAL_SCROLL_STRATEGY,
|
||||
useFactory: _cipherListVirtualScrollStrategyFactory,
|
||||
deps: [forwardRef(() => CipherListVirtualScroll)],
|
||||
}],
|
||||
selector: "cdk-virtual-scroll-viewport[itemSize]",
|
||||
providers: [
|
||||
{
|
||||
provide: VIRTUAL_SCROLL_STRATEGY,
|
||||
useFactory: _cipherListVirtualScrollStrategyFactory,
|
||||
deps: [forwardRef(() => CipherListVirtualScroll)],
|
||||
},
|
||||
],
|
||||
})
|
||||
export class CipherListVirtualScroll extends CdkFixedSizeVirtualScroll {
|
||||
_scrollStrategy: CipherListVirtualScrollStrategy;
|
||||
_scrollStrategy: CipherListVirtualScrollStrategy;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._scrollStrategy = new CipherListVirtualScrollStrategy(this.itemSize, this.minBufferPx, this.maxBufferPx,
|
||||
this.checkAndUpdateItemSize);
|
||||
}
|
||||
|
||||
checkAndUpdateItemSize = () => {
|
||||
const sampleItem = document.querySelector('cdk-virtual-scroll-viewport .virtual-scroll-item') as HTMLElement;
|
||||
const newItemSize = sampleItem?.offsetHeight;
|
||||
|
||||
if (newItemSize != null && newItemSize !== this.itemSize) {
|
||||
this.itemSize = newItemSize;
|
||||
this._scrollStrategy.updateItemAndBufferSize(this.itemSize, this.minBufferPx, this.maxBufferPx);
|
||||
}
|
||||
constructor() {
|
||||
super();
|
||||
this._scrollStrategy = new CipherListVirtualScrollStrategy(
|
||||
this.itemSize,
|
||||
this.minBufferPx,
|
||||
this.maxBufferPx,
|
||||
this.checkAndUpdateItemSize
|
||||
);
|
||||
}
|
||||
|
||||
checkAndUpdateItemSize = () => {
|
||||
const sampleItem = document.querySelector(
|
||||
"cdk-virtual-scroll-viewport .virtual-scroll-item"
|
||||
) as HTMLElement;
|
||||
const newItemSize = sampleItem?.offsetHeight;
|
||||
|
||||
if (newItemSize != null && newItemSize !== this.itemSize) {
|
||||
this.itemSize = newItemSize;
|
||||
this._scrollStrategy.updateItemAndBufferSize(
|
||||
this.itemSize,
|
||||
this.minBufferPx,
|
||||
this.maxBufferPx
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
Input,
|
||||
} from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, Input } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: '[appFallbackSrc]',
|
||||
selector: "[appFallbackSrc]",
|
||||
})
|
||||
export class FallbackSrcDirective {
|
||||
@Input('appFallbackSrc') appFallbackSrc: string;
|
||||
@Input("appFallbackSrc") appFallbackSrc: string;
|
||||
|
||||
constructor(private el: ElementRef) {
|
||||
}
|
||||
constructor(private el: ElementRef) {}
|
||||
|
||||
@HostListener('error') onError() {
|
||||
this.el.nativeElement.src = this.appFallbackSrc;
|
||||
}
|
||||
@HostListener("error") onError() {
|
||||
this.el.nativeElement.src = this.appFallbackSrc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,32 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
Input,
|
||||
Renderer2,
|
||||
} from '@angular/core';
|
||||
import { Directive, ElementRef, Input, Renderer2 } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: '[appInputVerbatim]',
|
||||
selector: "[appInputVerbatim]",
|
||||
})
|
||||
export class InputVerbatimDirective {
|
||||
@Input() set appInputVerbatim(condition: boolean | string) {
|
||||
this.disableComplete = condition === '' || condition === true;
|
||||
@Input() set appInputVerbatim(condition: boolean | string) {
|
||||
this.disableComplete = condition === "" || condition === true;
|
||||
}
|
||||
|
||||
private disableComplete: boolean;
|
||||
|
||||
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.disableComplete && !this.el.nativeElement.hasAttribute("autocomplete")) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "autocomplete", "off");
|
||||
}
|
||||
|
||||
private disableComplete: boolean;
|
||||
|
||||
constructor(private el: ElementRef, private renderer: Renderer2) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (this.disableComplete && !this.el.nativeElement.hasAttribute('autocomplete')) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, 'autocomplete', 'off');
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute('autocapitalize')) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, 'autocapitalize', 'none');
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute('autocorrect')) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, 'autocorrect', 'none');
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute('spellcheck')) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, 'spellcheck', 'false');
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute('inputmode')) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, 'inputmode', 'verbatim');
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute("autocapitalize")) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "autocapitalize", "none");
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute("autocorrect")) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "autocorrect", "none");
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute("spellcheck")) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "spellcheck", "false");
|
||||
}
|
||||
if (!this.el.nativeElement.hasAttribute("inputmode")) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "inputmode", "verbatim");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,37 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
} from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener } from "@angular/core";
|
||||
|
||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
|
||||
@Directive({
|
||||
selector: '[appSelectCopy]',
|
||||
selector: "[appSelectCopy]",
|
||||
})
|
||||
export class SelectCopyDirective {
|
||||
constructor(private el: ElementRef, private platformUtilsService: PlatformUtilsService) { }
|
||||
constructor(private el: ElementRef, private platformUtilsService: PlatformUtilsService) {}
|
||||
|
||||
@HostListener('copy') onCopy() {
|
||||
if (window == null) {
|
||||
return;
|
||||
}
|
||||
let copyText = '';
|
||||
const selection = window.getSelection();
|
||||
for (let i = 0; i < selection.rangeCount; i++) {
|
||||
const range = selection.getRangeAt(i);
|
||||
const text = range.toString();
|
||||
|
||||
// The selection should only contain one line of text. In some cases however, the
|
||||
// selection contains newlines and space characters from the indentation of following
|
||||
// sibling nodes. To avoid copying passwords containing trailing newlines and spaces
|
||||
// that aren't part of the password, the selection has to be trimmed.
|
||||
let stringEndPos = text.length;
|
||||
const newLinePos = text.search(/(?:\r\n|\r|\n)/);
|
||||
if (newLinePos > -1) {
|
||||
const otherPart = text.substr(newLinePos).trim();
|
||||
if (otherPart === '') {
|
||||
stringEndPos = newLinePos;
|
||||
}
|
||||
}
|
||||
copyText += text.substring(0, stringEndPos);
|
||||
}
|
||||
this.platformUtilsService.copyToClipboard(copyText, { window: window });
|
||||
@HostListener("copy") onCopy() {
|
||||
if (window == null) {
|
||||
return;
|
||||
}
|
||||
let copyText = "";
|
||||
const selection = window.getSelection();
|
||||
for (let i = 0; i < selection.rangeCount; i++) {
|
||||
const range = selection.getRangeAt(i);
|
||||
const text = range.toString();
|
||||
|
||||
// The selection should only contain one line of text. In some cases however, the
|
||||
// selection contains newlines and space characters from the indentation of following
|
||||
// sibling nodes. To avoid copying passwords containing trailing newlines and spaces
|
||||
// that aren't part of the password, the selection has to be trimmed.
|
||||
let stringEndPos = text.length;
|
||||
const newLinePos = text.search(/(?:\r\n|\r|\n)/);
|
||||
if (newLinePos > -1) {
|
||||
const otherPart = text.substr(newLinePos).trim();
|
||||
if (otherPart === "") {
|
||||
stringEndPos = newLinePos;
|
||||
}
|
||||
}
|
||||
copyText += text.substring(0, stringEndPos);
|
||||
}
|
||||
this.platformUtilsService.copyToClipboard(copyText, { window: window });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import {
|
||||
Directive,
|
||||
HostListener,
|
||||
} from '@angular/core';
|
||||
import { Directive, HostListener } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: '[appStopClick]',
|
||||
selector: "[appStopClick]",
|
||||
})
|
||||
export class StopClickDirective {
|
||||
@HostListener('click', ['$event']) onClick($event: MouseEvent) {
|
||||
$event.preventDefault();
|
||||
}
|
||||
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
||||
$event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import {
|
||||
Directive,
|
||||
HostListener,
|
||||
} from '@angular/core';
|
||||
import { Directive, HostListener } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: '[appStopProp]',
|
||||
selector: "[appStopProp]",
|
||||
})
|
||||
export class StopPropDirective {
|
||||
@HostListener('click', ['$event']) onClick($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,49 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
forwardRef,
|
||||
HostListener,
|
||||
Input,
|
||||
Renderer2,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
NgControl,
|
||||
NG_VALUE_ACCESSOR,
|
||||
} from '@angular/forms';
|
||||
import { Directive, ElementRef, forwardRef, HostListener, Input, Renderer2 } from "@angular/core";
|
||||
import { ControlValueAccessor, NgControl, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||
|
||||
// ref: https://juristr.com/blog/2018/02/ng-true-value-directive/
|
||||
@Directive({
|
||||
selector: 'input[type=checkbox][appTrueFalseValue]',
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => TrueFalseValueDirective),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
selector: "input[type=checkbox][appTrueFalseValue]",
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => TrueFalseValueDirective),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class TrueFalseValueDirective implements ControlValueAccessor {
|
||||
@Input() trueValue = true;
|
||||
@Input() falseValue = false;
|
||||
@Input() trueValue = true;
|
||||
@Input() falseValue = false;
|
||||
|
||||
constructor(private elementRef: ElementRef, private renderer: Renderer2) { }
|
||||
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}
|
||||
|
||||
@HostListener('change', ['$event'])
|
||||
onHostChange(ev: any) {
|
||||
this.propagateChange(ev.target.checked ? this.trueValue : this.falseValue);
|
||||
@HostListener("change", ["$event"])
|
||||
onHostChange(ev: any) {
|
||||
this.propagateChange(ev.target.checked ? this.trueValue : this.falseValue);
|
||||
}
|
||||
|
||||
writeValue(obj: any): void {
|
||||
if (obj === this.trueValue) {
|
||||
this.renderer.setProperty(this.elementRef.nativeElement, "checked", true);
|
||||
} else {
|
||||
this.renderer.setProperty(this.elementRef.nativeElement, "checked", false);
|
||||
}
|
||||
}
|
||||
|
||||
writeValue(obj: any): void {
|
||||
if (obj === this.trueValue) {
|
||||
this.renderer.setProperty(this.elementRef.nativeElement, 'checked', true);
|
||||
} else {
|
||||
this.renderer.setProperty(this.elementRef.nativeElement, 'checked', false);
|
||||
}
|
||||
}
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
}
|
||||
registerOnTouched(fn: any): void {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
registerOnTouched(fn: any): void { /* nothing */ }
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
setDisabledState?(isDisabled: boolean): void { /* nothing */ }
|
||||
|
||||
private propagateChange = (_: any) => { /* nothing */ };
|
||||
private propagateChange = (_: any) => {
|
||||
/* nothing */
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user