Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/scripts/background/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export async function handleExtensionInstalled(): Promise<void> {
active: false,
allowedPlattform: donationAllowed,
},
pointListStyle: "docCategories"
});

await checkIfUpdateNeeded(true);
Expand Down
223 changes: 160 additions & 63 deletions src/scripts/views/popup/service.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import { getApiUrl, getLanguage, isCuratorMode } from './state';
import { getApiUrl, getLanguage, isCuratorMode, getpointListStyle } from './state';
import { applyHeaderColor } from './theme';

interface ServicePoint {
status: string;
title: string;
case?: {
case: {
classification?: string;
localized_title?: string | null;
};
document_id?: number
}

interface ServiceDocument {
id: number
name: string
url: string
}

interface ServiceResponse {
name: string;
rating?: string;
points: ServicePoint[];
documents: ServiceDocument[]
}

interface SearchResponse {
Expand Down Expand Up @@ -52,7 +60,15 @@ export async function displayServiceDetails(
updatePointsCount(data.points.length);
revealLoadedState(options.unverified === true);

populateList(data.points);
if (getpointListStyle() === "docCategories") {
populateListDocCategories(data.points, data.documents);
} else if (getpointListStyle() === "unified") {
populateListUnified(data.points)
} else {
console.error("Unsupported pointListStyle", getpointListStyle());
}


} catch (error) {
hideLoadingState();
showErrorOverlay(
Expand Down Expand Up @@ -164,7 +180,19 @@ function revealLoadedState(unverified: boolean): void {
}
}

function populateList(points: ServicePoint[]): void {
function populateListUnified(allPoints: ServicePoint[]) {
const documentList = document.getElementById('documentList');
const doc = document.createElement('div');
const temp = `
<div class="">
<div id="pointList" class="pointList">
<a style="display: none">...</a>
/div>
</div>`
;
doc.innerHTML = temp.trim();
documentList!.appendChild(doc.firstChild!);

const pointsList = document.getElementById('pointList');
if (!pointsList) {
return;
Expand All @@ -173,79 +201,148 @@ function populateList(points: ServicePoint[]): void {
pointsList.style.display = 'block';
pointsList.innerHTML = '';

const filteredPoints = filterPoints(points);

appendPointGroup(filteredPoints.blocker, pointsList, false);
appendPointGroup(filteredPoints.bad, pointsList, false);
appendPointGroup(filteredPoints.good, pointsList, false);
appendPointGroup(filteredPoints.neutral, pointsList, true);
}
const filteredPoints = filterPoints(allPoints);

function filterPoints(points: ServicePoint[]): {
blocker: ServicePoint[];
bad: ServicePoint[];
good: ServicePoint[];
neutral: ServicePoint[];
} {
const curatedPoints = points.filter((point) => {
if (!isCuratorMode()) {
return point.status === 'approved';
}
return point.status === 'approved' || point.status === 'pending';
});

return {
blocker: curatedPoints.filter(
(point) => point.case?.classification === 'blocker'
),
bad: curatedPoints.filter(
(point) => point.case?.classification === 'bad'
),
good: curatedPoints.filter(
(point) => point.case?.classification === 'good'
),
neutral: curatedPoints.filter(
(point) => point.case?.classification === 'neutral'
),
};
createPointList(filteredPoints.blocker, pointsList, false);
createPointList(filteredPoints.bad, pointsList, false);
createPointList(filteredPoints.good, pointsList, false);
createPointList(filteredPoints.neutral, pointsList, true);
}

function appendPointGroup(
points: ServicePoint[],
container: HTMLElement,
isLastGroup: boolean
): void {
let added = 0;

points.forEach((point, index) => {
const wrapper = document.createElement('div');
const classification = point.case?.classification ?? 'neutral';
const pointTitle = point.case?.localized_title ?? point.title;
wrapper.innerHTML = `
<div class="point ${classification}">
<img src="icons/${classification}.svg">
<p>${pointTitle}</p>
${renderCuratorTag(point.status)}
function populateListDocCategories(allPoints: ServicePoint[], documents: ServiceDocument[]) {
const documentList = document.getElementById('documentList');
// Split points by Document and display them seperatly
for (let i of documents) {
const element = i;

const docPoints = allPoints.filter((point:ServicePoint) => point.document_id === element.id)
const sortedPoints = filterPoints(docPoints)

if (sortedPoints.blocker.length + sortedPoints.bad.length + sortedPoints.neutral.length + sortedPoints.good.length > 0) {
const doc = document.createElement('div');
const temp = `
<div class="">
<div class="documentHeader">
<h3 class="documentTitle">${element.name}</h3>
<a href="${element.url}" target="_blank">Read Original></a>
</div>
<div id="pointList_${element.id}" class="pointList">
<a style="display: none">...</a>
</div>
</div>`;
doc.innerHTML = temp.trim();
documentList!.appendChild(doc.firstChild!);

const pointsList = document.getElementById(`pointList_${element.id}`)!

createSortetPoints(sortedPoints,pointsList)
} else { //documents without points
const docsWithoutPointsWraper = document.getElementById('docsWithoutPointsWraper')
const docsWithoutPoints = document.getElementById('docsWithoutPoints')

if (docsWithoutPoints?.style.display === "none") {
docsWithoutPoints.style.display = "block"
}
const doc = document.createElement('div');
const temp = `
<div class="documentHeader">
<h3 class="documentTitle">${element.name}</h3>
<a href="${element.url}" target="_blank">Read Original></a>
</div>`;
doc.innerHTML = temp.trim();
docsWithoutPointsWraper!.appendChild(doc.firstChild!);
}
}
//display points not liked to a document
const noDocPoints = allPoints.filter((point: ServicePoint) => point.document_id === null)
if (noDocPoints.length > 0) {
const doc = document.createElement('div');
const temp = `
<div class="">
<div class="documentHeader">
<h3 class="documentTitle">Points not linked to a Document</h3>
</div>
`.trim();
if (wrapper.firstChild) {
container.appendChild(wrapper.firstChild as HTMLElement);
<div id="pointList_unlinkedPoints" class="pointList">
<a style="display: none">...</a>
</div>
</div>`;
doc.innerHTML = temp.trim();
documentList!.appendChild(doc.firstChild!);
const sortedPoints = filterPoints(noDocPoints)
const pointsList = document.getElementById(`pointList_unlinkedPoints`)!
createSortetPoints(sortedPoints,pointsList)

}
}
function filterPoints(points:ServicePoint[]) {
if (isCuratorMode()) {
points = points.filter(
(point) =>
point.status === 'approved' || point.status === 'pending'
);
} else {
points = points.filter((point) => point.status === 'approved');
}
added += 1;
let filteredPoints:any = {}
filteredPoints.blocker = points.filter(
(point) => point.case.classification === 'blocker'
);
filteredPoints.bad = points.filter(
(point) => point.case.classification === 'bad'
);
filteredPoints.good = points.filter(
(point) => point.case.classification === 'good'
);
filteredPoints.neutral = points.filter(
(point) => point.case.classification === 'neutral'
);
return filteredPoints
}

function createSortetPoints(sortedPoints:any,pointsList:HTMLElement) {
if (sortedPoints.blocker) {
createPointList(sortedPoints.blocker, pointsList, false);
}
if (sortedPoints.bad) {
createPointList(sortedPoints.bad, pointsList, false);
}
if (sortedPoints.good) {
createPointList(sortedPoints.good, pointsList, false);
}
if (sortedPoints.neutral) {
createPointList(sortedPoints.neutral, pointsList, true);
}
}

if (index !== points.length - 1) {
function createPointList(pointsFiltered: ServicePoint[], pointsList: HTMLElement, last: boolean) {
let added = 0;
for (let i = 0; i < pointsFiltered.length; i++) {
const point = document.createElement('div');
const pointTitle = pointsFiltered[i]!.case?.localized_title ?? pointsFiltered[i]!.title;

let temp = `
<div class="point ${pointsFiltered[i]!.case.classification}">
<img src="icons/${pointsFiltered[i]!.case.classification}.svg">
<p>${pointTitle}</p>
${renderCuratorTag(pointsFiltered[i]!.status)}
</div>`;
point.innerHTML = temp.trim();
pointsList.appendChild(point.firstChild!);
added++;
if (i !== pointsFiltered.length - 1) {
const divider = document.createElement('hr');
container.appendChild(divider);
pointsList.appendChild(divider);
}
});

if (added > 0 && !isLastGroup) {
}
if (added !== 0 && !last) {
const divider = document.createElement('hr');
divider.classList.add('group');
container.appendChild(divider);
pointsList.appendChild(divider);
}
}


function renderCuratorTag(status: string): string {
if (!isCuratorMode() || status === 'approved') {
return '';
Expand Down
10 changes: 9 additions & 1 deletion src/scripts/views/popup/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import {
let curatorMode = false;
let apiUrl = DEFAULT_API_URL;
let language: SupportedLanguage = 'en';
let pointListStyle:"docCategories" | "unified"

export interface PopupPreferences {
darkmode: boolean;
curatorMode: boolean;
language: SupportedLanguage;
pointListStyle:"docCategories" | "unified"
}

export function isCuratorMode(): boolean {
Expand All @@ -31,11 +33,16 @@ export function setApiUrl(url: string): void {
apiUrl = url;
}

export function getpointListStyle() {
return pointListStyle
}

export async function hydrateState(): Promise<PopupPreferences> {
const result = await getLocal(['darkmode', 'curatorMode', 'api', 'language']);
const result = await getLocal(['darkmode', 'curatorMode', 'api', 'language', 'pointListStyle']);

const darkmode = Boolean(result['darkmode']);
const storedCuratorMode = Boolean(result['curatorMode']);
pointListStyle = result['pointListStyle'] as "docCategories" | "unified"
setCuratorMode(storedCuratorMode);

const api = result['api'];
Expand All @@ -52,6 +59,7 @@ export async function hydrateState(): Promise<PopupPreferences> {
darkmode,
curatorMode: storedCuratorMode,
language: resolvedLanguage,
pointListStyle,
};
}

Expand Down
12 changes: 12 additions & 0 deletions src/scripts/views/settings/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export function registerSettingsHandlers(): void {
const curatorModeInput = document.getElementById('curatorMode') as HTMLInputElement | null;
const apiInput = document.getElementById('api') as HTMLInputElement | null;
const languageSelect = document.getElementById('language') as HTMLSelectElement | null;
const pointListStyleSelect = document.getElementById('pointListStyle') as HTMLSelectElement | null;


if (updateInput) {
updateInput.addEventListener('change', () => {
Expand Down Expand Up @@ -52,4 +54,14 @@ export function registerSettingsHandlers(): void {
void setLocal({ language: normalized });
});
}

if (pointListStyleSelect) {
pointListStyleSelect.addEventListener('change', () => {
const normalized = pointListStyleSelect.value ?? 'docCategories';
if (pointListStyleSelect.value !== normalized) {
pointListStyleSelect.value = normalized;
}
void setLocal({ pointListStyle: normalized });
});
}
}
5 changes: 5 additions & 0 deletions src/scripts/views/settings/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export async function populateSettingsForm(): Promise<void> {
'sentry',
'api',
'language',
'pointListStyle'
]);

if (Array.isArray(result['db'])) {
Expand Down Expand Up @@ -56,6 +57,9 @@ export async function populateSettingsForm(): Promise<void> {
const language = resolveLanguage(result['language']);
elements.languageSelect.value = language;
}
if (elements.pointListStyle) {
elements.pointListStyle.value = String(result['pointListStyle']);
}
}

function collectElements() {
Expand All @@ -69,6 +73,7 @@ function collectElements() {
date: document.getElementById('date') as HTMLElement | null,
indexed: document.getElementById('indexed') as HTMLElement | null,
days: document.getElementById('days') as HTMLElement | null,
pointListStyle: document.getElementById('pointListStyle') as HTMLSelectElement | null
};
}

Expand Down
10 changes: 8 additions & 2 deletions src/views/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,15 @@ <h3 style="display: none">
Points for <a class="serviceName">...</a>:
</h3>

<div id="pointList">
<div id="documentList">
<a style="display: none">...</a>
</div>
<div style="display: none;" id="docsWithoutPoints">
<div class="documentHeader">
<h3 class="documentTitle">Documents without Points</h3>
</div>
<div id="docsWithoutPointsWraper" class="pointList"></div>
</div>
<a>
<button id="toggleButton">Toggle Darkmode</button> -
<button id="settingsButton">Settings</button> -
Expand All @@ -116,5 +122,5 @@ <h3 style="display: none">
Translations are machine translated. You can turn them off in Settings by choosing English.
</p>
</body>
<script type="module" src="../scripts/views/popup.js"></script>
<script type="module" src="../scripts/views/popup.js" defer></script>
</html>
Loading