chrome-devtools-frontend
Version:
Chrome DevTools UI
164 lines (140 loc) • 5.03 kB
text/typescript
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export const enum AdornerCategories {
SECURITY = 'Security',
LAYOUT = 'Layout',
DEFAULT = 'Default',
}
export interface AdornerSetting {
adorner: string;
isEnabled: boolean;
}
export type AdornerSettingsMap = Map<string, boolean>;
export interface RegisteredAdorner {
readonly name: string;
readonly category: AdornerCategories;
readonly enabledByDefault: boolean;
}
// TODO(crbug.com/1167717): Make this a const enum again
// eslint-disable-next-line rulesdir/const_enum
export enum RegisteredAdorners {
GRID = 'grid',
FLEX = 'flex',
AD = 'ad',
SCROLL_SNAP = 'scroll-snap',
CONTAINER = 'container',
}
// This enum-like const object serves as the authoritative registry for all the
// adorners available.
export function getRegisteredAdorner(which: RegisteredAdorners): RegisteredAdorner {
switch (which) {
case RegisteredAdorners.GRID:
return {
name: 'grid',
category: AdornerCategories.LAYOUT,
enabledByDefault: true,
};
case RegisteredAdorners.FLEX:
return {
name: 'flex',
category: AdornerCategories.LAYOUT,
enabledByDefault: true,
};
case RegisteredAdorners.AD:
return {
name: 'ad',
category: AdornerCategories.SECURITY,
enabledByDefault: true,
};
case RegisteredAdorners.SCROLL_SNAP:
return {
name: 'scroll-snap',
category: AdornerCategories.LAYOUT,
enabledByDefault: true,
};
case RegisteredAdorners.CONTAINER:
return {
name: 'container',
category: AdornerCategories.LAYOUT,
enabledByDefault: true,
};
}
}
let adornerNameToCategoryMap: Map<string, AdornerCategories>|undefined = undefined;
function getCategoryFromAdornerName(name: string): AdornerCategories {
if (!adornerNameToCategoryMap) {
adornerNameToCategoryMap = new Map();
for (const {name, category} of Object.values(RegisteredAdorners).map(getRegisteredAdorner)) {
adornerNameToCategoryMap.set(name, category);
}
}
return adornerNameToCategoryMap.get(name) || AdornerCategories.DEFAULT;
}
export const DefaultAdornerSettings: AdornerSetting[] =
Object.values(RegisteredAdorners).map(getRegisteredAdorner).map(({name, enabledByDefault}) => ({
adorner: name,
isEnabled: enabledByDefault,
}));
interface SettingStore<Setting> {
get(): Setting;
set(setting: Setting): void;
}
export class AdornerManager {
private adornerSettings: AdornerSettingsMap = new Map();
private settingStore: SettingStore<AdornerSetting[]>;
constructor(settingStore: SettingStore<AdornerSetting[]>) {
this.settingStore = settingStore;
this.syncSettings();
}
updateSettings(settings: AdornerSettingsMap): void {
this.adornerSettings = settings;
this.persistCurrentSettings();
}
getSettings(): Readonly<AdornerSettingsMap> {
return this.adornerSettings;
}
isAdornerEnabled(adornerText: string): boolean {
return this.adornerSettings.get(adornerText) || false;
}
private persistCurrentSettings(): void {
const settingList = [];
for (const [adorner, isEnabled] of this.adornerSettings) {
settingList.push({adorner, isEnabled});
}
this.settingStore.set(settingList);
}
private loadSettings(): void {
const settingList = this.settingStore.get();
for (const setting of settingList) {
this.adornerSettings.set(setting.adorner, setting.isEnabled);
}
}
private syncSettings(): void {
this.loadSettings();
// Prune outdated adorners and add new ones to the persistence.
const outdatedAdorners = new Set(this.adornerSettings.keys());
for (const {adorner, isEnabled} of DefaultAdornerSettings) {
outdatedAdorners.delete(adorner);
if (!this.adornerSettings.has(adorner)) {
this.adornerSettings.set(adorner, isEnabled);
}
}
for (const outdatedAdorner of outdatedAdorners) {
this.adornerSettings.delete(outdatedAdorner);
}
this.persistCurrentSettings();
}
}
const OrderedAdornerCategories = [
AdornerCategories.SECURITY,
AdornerCategories.LAYOUT,
AdornerCategories.DEFAULT,
];
// Use idx + 1 for the order to avoid JavaScript's 0 == false issue
export const AdornerCategoryOrder = new Map(OrderedAdornerCategories.map((category, idx) => [category, idx + 1]));
export function compareAdornerNamesByCategory(nameA: string, nameB: string): number {
const orderA = AdornerCategoryOrder.get(getCategoryFromAdornerName(nameA)) || Number.POSITIVE_INFINITY;
const orderB = AdornerCategoryOrder.get(getCategoryFromAdornerName(nameB)) || Number.POSITIVE_INFINITY;
return orderA - orderB;
}