mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 06:43:35 +00:00
Move to libs
This commit is contained in:
19
libs/angular/src/pipes/color-password-count.pipe.ts
Normal file
19
libs/angular/src/pipes/color-password-count.pipe.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Pipe } from "@angular/core";
|
||||
|
||||
import { ColorPasswordPipe } from "./color-password.pipe";
|
||||
|
||||
/*
|
||||
An updated pipe that extends ColourPasswordPipe to include a character count
|
||||
*/
|
||||
@Pipe({ name: "colorPasswordCount" })
|
||||
export class ColorPasswordCountPipe extends ColorPasswordPipe {
|
||||
transform(password: string) {
|
||||
const template = (character: string, type: string, index: number) =>
|
||||
`<span class="password-character password-${type}">
|
||||
${character}<span class="password-count">${index + 1}</span>
|
||||
</span>`;
|
||||
const colorizedPasswordCount = this.generateTemplate(password, template);
|
||||
|
||||
return colorizedPasswordCount;
|
||||
}
|
||||
}
|
||||
61
libs/angular/src/pipes/color-password.pipe.ts
Normal file
61
libs/angular/src/pipes/color-password.pipe.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
|
||||
/*
|
||||
An updated pipe that sanitizes HTML, highlights numbers and special characters (in different colors each)
|
||||
and handles Unicode / Emoji characters correctly.
|
||||
*/
|
||||
@Pipe({ name: "colorPassword" })
|
||||
export class ColorPasswordPipe implements PipeTransform {
|
||||
transform(password: string) {
|
||||
const template = (character: string, type: string) =>
|
||||
`<span class="password-${type}">${character}</span>`;
|
||||
const colorizedPassword = this.generateTemplate(password, template);
|
||||
return colorizedPassword;
|
||||
}
|
||||
|
||||
protected generateTemplate(
|
||||
password: string,
|
||||
templateGenerator: (chararacter: string, type: string, index?: number) => string
|
||||
) {
|
||||
// Convert to an array to handle cases that stings have special characters, ie: emoji.
|
||||
const passwordArray = Array.from(password);
|
||||
let colorizedPassword = "";
|
||||
for (let i = 0; i < passwordArray.length; i++) {
|
||||
let character = passwordArray[i];
|
||||
let isSpecial = false;
|
||||
// Sanitize HTML first.
|
||||
switch (character) {
|
||||
case "&":
|
||||
character = "&";
|
||||
isSpecial = true;
|
||||
break;
|
||||
case "<":
|
||||
character = "<";
|
||||
isSpecial = true;
|
||||
break;
|
||||
case ">":
|
||||
character = ">";
|
||||
isSpecial = true;
|
||||
break;
|
||||
case " ":
|
||||
character = " ";
|
||||
isSpecial = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
let type = "letter";
|
||||
if (character.match(Utils.regexpEmojiPresentation)) {
|
||||
type = "emoji";
|
||||
} else if (isSpecial || character.match(/[^\w ]/)) {
|
||||
type = "special";
|
||||
} else if (character.match(/\d/)) {
|
||||
type = "number";
|
||||
}
|
||||
colorizedPassword += templateGenerator(character, type, i);
|
||||
}
|
||||
return colorizedPassword;
|
||||
}
|
||||
}
|
||||
64
libs/angular/src/pipes/credit-card-number.pipe.ts
Normal file
64
libs/angular/src/pipes/credit-card-number.pipe.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
interface CardRuleEntry {
|
||||
cardLength: number;
|
||||
blocks: number[];
|
||||
}
|
||||
|
||||
// See https://baymard.com/checkout-usability/credit-card-patterns for
|
||||
// all possible credit card spacing patterns. For now, we just handle
|
||||
// the below.
|
||||
const numberFormats: Record<string, CardRuleEntry[]> = {
|
||||
Visa: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
|
||||
Mastercard: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
|
||||
Maestro: [
|
||||
{ cardLength: 16, blocks: [4, 4, 4, 4] },
|
||||
{ cardLength: 13, blocks: [4, 4, 5] },
|
||||
{ cardLength: 15, blocks: [4, 6, 5] },
|
||||
{ cardLength: 19, blocks: [4, 4, 4, 4, 3] },
|
||||
],
|
||||
Discover: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
|
||||
"Diners Club": [{ cardLength: 14, blocks: [4, 6, 4] }],
|
||||
JCB: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
|
||||
UnionPay: [
|
||||
{ cardLength: 16, blocks: [4, 4, 4, 4] },
|
||||
{ cardLength: 19, blocks: [6, 13] },
|
||||
],
|
||||
Amex: [{ cardLength: 15, blocks: [4, 6, 5] }],
|
||||
Other: [{ cardLength: 16, blocks: [4, 4, 4, 4] }],
|
||||
};
|
||||
|
||||
@Pipe({ name: "creditCardNumber" })
|
||||
export class CreditCardNumberPipe implements PipeTransform {
|
||||
transform(creditCardNumber: string, brand: string): string {
|
||||
let rules = numberFormats[brand];
|
||||
|
||||
if (rules == null) {
|
||||
rules = numberFormats["Other"];
|
||||
}
|
||||
|
||||
const cardLength = creditCardNumber.length;
|
||||
|
||||
let matchingRule = rules.find((r) => r.cardLength == cardLength);
|
||||
if (matchingRule == null) {
|
||||
matchingRule = rules[0];
|
||||
}
|
||||
|
||||
const blocks = matchingRule.blocks;
|
||||
|
||||
const chunks: string[] = [];
|
||||
let total = 0;
|
||||
|
||||
blocks.forEach((c) => {
|
||||
chunks.push(creditCardNumber.slice(total, total + c));
|
||||
total += c;
|
||||
});
|
||||
|
||||
// Append the remaining part
|
||||
if (cardLength > total) {
|
||||
chunks.push(creditCardNumber.slice(total));
|
||||
}
|
||||
|
||||
return chunks.join(" ");
|
||||
}
|
||||
}
|
||||
17
libs/angular/src/pipes/ellipsis.pipe.ts
Normal file
17
libs/angular/src/pipes/ellipsis.pipe.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
@Pipe({
|
||||
name: "ellipsis",
|
||||
})
|
||||
export class EllipsisPipe implements PipeTransform {
|
||||
transform(value: string, limit = 25, completeWords = false, ellipsis = "...") {
|
||||
if (value.length <= limit) {
|
||||
return value;
|
||||
}
|
||||
limit -= ellipsis.length;
|
||||
if (completeWords && value.length > limit && value.indexOf(" ") > 0) {
|
||||
limit = value.substring(0, limit).lastIndexOf(" ");
|
||||
}
|
||||
return value.substring(0, limit) + ellipsis;
|
||||
}
|
||||
}
|
||||
14
libs/angular/src/pipes/i18n.pipe.ts
Normal file
14
libs/angular/src/pipes/i18n.pipe.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
|
||||
@Pipe({
|
||||
name: "i18n",
|
||||
})
|
||||
export class I18nPipe implements PipeTransform {
|
||||
constructor(private i18nService: I18nService) {}
|
||||
|
||||
transform(id: string, p1?: string, p2?: string, p3?: string): string {
|
||||
return this.i18nService.t(id, p1, p2, p3);
|
||||
}
|
||||
}
|
||||
41
libs/angular/src/pipes/search-ciphers.pipe.ts
Normal file
41
libs/angular/src/pipes/search-ciphers.pipe.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||
|
||||
@Pipe({
|
||||
name: "searchCiphers",
|
||||
})
|
||||
export class SearchCiphersPipe implements PipeTransform {
|
||||
transform(ciphers: CipherView[], searchText: string, deleted = false): CipherView[] {
|
||||
if (ciphers == null || ciphers.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (searchText == null || searchText.length < 2) {
|
||||
return ciphers.filter((c) => {
|
||||
return deleted !== c.isDeleted;
|
||||
});
|
||||
}
|
||||
|
||||
searchText = searchText.trim().toLowerCase();
|
||||
return ciphers.filter((c) => {
|
||||
if (deleted !== c.isDeleted) {
|
||||
return false;
|
||||
}
|
||||
if (c.name != null && c.name.toLowerCase().indexOf(searchText) > -1) {
|
||||
return true;
|
||||
}
|
||||
if (searchText.length >= 8 && c.id.startsWith(searchText)) {
|
||||
return true;
|
||||
}
|
||||
if (c.subTitle != null && c.subTitle.toLowerCase().indexOf(searchText) > -1) {
|
||||
return true;
|
||||
}
|
||||
if (c.login && c.login.uri != null && c.login.uri.toLowerCase().indexOf(searchText) > -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
48
libs/angular/src/pipes/search.pipe.ts
Normal file
48
libs/angular/src/pipes/search.pipe.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
@Pipe({
|
||||
name: "search",
|
||||
})
|
||||
export class SearchPipe implements PipeTransform {
|
||||
transform(
|
||||
items: any[],
|
||||
searchText: string,
|
||||
prop1?: string,
|
||||
prop2?: string,
|
||||
prop3?: string
|
||||
): any[] {
|
||||
if (items == null || items.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (searchText == null || searchText.length < 2) {
|
||||
return items;
|
||||
}
|
||||
|
||||
searchText = searchText.trim().toLowerCase();
|
||||
return items.filter((i) => {
|
||||
if (
|
||||
prop1 != null &&
|
||||
i[prop1] != null &&
|
||||
i[prop1].toString().toLowerCase().indexOf(searchText) > -1
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
prop2 != null &&
|
||||
i[prop2] != null &&
|
||||
i[prop2].toString().toLowerCase().indexOf(searchText) > -1
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
prop3 != null &&
|
||||
i[prop3] != null &&
|
||||
i[prop3].toString().toLowerCase().indexOf(searchText) > -1
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
19
libs/angular/src/pipes/user-name.pipe.ts
Normal file
19
libs/angular/src/pipes/user-name.pipe.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
interface User {
|
||||
name?: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
@Pipe({
|
||||
name: "userName",
|
||||
})
|
||||
export class UserNamePipe implements PipeTransform {
|
||||
transform(user?: User): string {
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return user.name == null || user.name.trim() === "" ? user.email : user.name;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user