1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 16:23:44 +00:00

Split jslib into multiple modules (#363)

* Split jslib into multiple modules
This commit is contained in:
Oscar Hinton
2021-06-03 18:58:57 +02:00
committed by GitHub
parent b1d9b84eae
commit 1016bbfb9e
509 changed files with 8838 additions and 1887 deletions

View File

@@ -0,0 +1,28 @@
import {
Directive,
ElementRef,
Input,
Renderer2,
} from '@angular/core';
@Directive({
selector: '[appA11yTitle]',
})
export class A11yTitleDirective {
@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);
}
if (!this.el.nativeElement.hasAttribute('aria-label')) {
this.renderer.setAttribute(this.el.nativeElement, 'aria-label', this.title);
}
}
}

View File

@@ -0,0 +1,32 @@
import {
Directive,
ElementRef,
Input,
OnChanges,
} from '@angular/core';
import { ValidationService } from '../services/validation.service';
@Directive({
selector: '[appApiAction]',
})
export class ApiActionDirective implements OnChanges {
@Input() appApiAction: Promise<any>;
constructor(private el: ElementRef, private validationService: ValidationService) { }
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;
this.validationService.showError(e);
});
}
}

View File

@@ -0,0 +1,26 @@
import {
Directive,
ElementRef,
Input,
} from '@angular/core';
import { Utils } from 'jslib-common/misc/utils';
@Directive({
selector: '[appAutofocus]',
})
export class AutofocusDirective {
@Input() set appAutofocus(condition: boolean | string) {
this.autofocus = condition === '' || condition === true;
}
private autofocus: boolean;
constructor(private el: ElementRef) { }
ngOnInit() {
if (!Utils.isMobileBrowser && this.autofocus) {
this.el.nativeElement.focus();
}
}
}

View File

@@ -0,0 +1,17 @@
import {
Directive,
ElementRef,
HostListener,
} from '@angular/core';
@Directive({
selector: '[appBlurClick]',
})
export class BlurClickDirective {
constructor(private el: ElementRef) {
}
@HostListener('click') onClick() {
this.el.nativeElement.blur();
}
}

View File

@@ -0,0 +1,51 @@
import {
Directive,
ElementRef,
HostListener,
OnInit,
} from '@angular/core';
@Directive({
selector: '[appBoxRow]',
})
export class BoxRowDirective implements OnInit {
el: HTMLElement = null;
formEls: Element[];
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;
}
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();
}
}
}

View File

@@ -0,0 +1,20 @@
import {
Directive,
ElementRef,
HostListener,
Input,
} from '@angular/core';
@Directive({
selector: '[appFallbackSrc]',
})
export class FallbackSrcDirective {
@Input('appFallbackSrc') appFallbackSrc: string;
constructor(private el: ElementRef) {
}
@HostListener('error') onError() {
this.el.nativeElement.src = this.appFallbackSrc;
}
}

View File

@@ -0,0 +1,37 @@
import {
Directive,
ElementRef,
Input,
Renderer2,
} from '@angular/core';
@Directive({
selector: '[appInputVerbatim]',
})
export class InputVerbatimDirective {
@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');
}
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');
}
}
}

View File

@@ -0,0 +1,41 @@
import {
Directive,
ElementRef,
HostListener,
} from '@angular/core';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
@Directive({
selector: '[appSelectCopy]',
})
export class SelectCopyDirective {
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 });
}
}

View File

@@ -0,0 +1,13 @@
import {
Directive,
HostListener,
} from '@angular/core';
@Directive({
selector: '[appStopClick]',
})
export class StopClickDirective {
@HostListener('click', ['$event']) onClick($event: MouseEvent) {
$event.preventDefault();
}
}

View File

@@ -0,0 +1,13 @@
import {
Directive,
HostListener,
} from '@angular/core';
@Directive({
selector: '[appStopProp]',
})
export class StopPropDirective {
@HostListener('click', ['$event']) onClick($event: MouseEvent) {
$event.stopPropagation();
}
}

View File

@@ -0,0 +1,54 @@
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,
},
],
})
export class TrueFalseValueDirective implements ControlValueAccessor {
@Input() trueValue = true;
@Input() falseValue = false;
constructor(private elementRef: ElementRef, private renderer: Renderer2) { }
@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);
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void { /* nothing */ }
setDisabledState?(isDisabled: boolean): void { /* nothing */ }
private propagateChange = (_: any) => { /* nothing */ };
}