fix: cleanup url, shadow with children slots

This commit is contained in:
Michal Szczepanski 2023-04-20 23:11:47 +02:00
parent b09b03edb0
commit ee53b501bf
35 changed files with 206 additions and 100 deletions

4
.env

@ -1,6 +1,4 @@
VERSION=1 VERSION=1
API_URL='https://pinmenote.com' WEB_URL=https://pinmenote.com
SHORT_URL='https://pmn.cl'
WEB_URL='https://pinmenote.com'
IS_PRODUCTION=true IS_PRODUCTION=true
OBJ_LIST_LIMIT=1000 OBJ_LIST_LIMIT=1000

@ -16,14 +16,20 @@
*/ */
import { BrowserStorageWrapper } from '../../../service/browser.storage.wrapper'; import { BrowserStorageWrapper } from '../../../service/browser.storage.wrapper';
import { ICommand } from '../../../model/shared/common.dto'; import { ICommand } from '../../../model/shared/common.dto';
import { ObjRemoveHashtagsCommand } from '../hashtag/obj-remove-hashtags.command';
import { ObjSnapshotDto } from '../../../model/obj/obj-snapshot.dto'; import { ObjSnapshotDto } from '../../../model/obj/obj-snapshot.dto';
import { ObjectStoreKeys } from '../../../keys/object.store.keys'; import { ObjectStoreKeys } from '../../../keys/object.store.keys';
import { WordNlp } from '../../../text/nlp/word.nlp';
export class ObjRemoveSnapshotContentCommand implements ICommand<Promise<void>> { export class ObjRemoveSnapshotContentCommand implements ICommand<Promise<void>> {
constructor(private snapshot: ObjSnapshotDto) {} constructor(private snapshot: ObjSnapshotDto, private id: number) {}
async execute(): Promise<void> { async execute(): Promise<void> {
const key = `${ObjectStoreKeys.CONTENT_ID}:${this.snapshot.contentId}`; const key = `${ObjectStoreKeys.CONTENT_ID}:${this.snapshot.contentId}`;
await WordNlp.removeFlat(this.snapshot.words, this.id);
await new ObjRemoveHashtagsCommand(this.id, this.snapshot.hashtags).execute();
await BrowserStorageWrapper.remove(key); await BrowserStorageWrapper.remove(key);
} }
} }

@ -24,6 +24,7 @@ import { ObjAddIdCommand } from '../obj/id/obj-add-id.command';
import { ObjNextIdCommand } from '../obj/id/obj-next-id.command'; import { ObjNextIdCommand } from '../obj/id/obj-next-id.command';
import { ObjPagePinDto } from '../../model/obj/obj-pin.dto'; import { ObjPagePinDto } from '../../model/obj/obj-pin.dto';
import { ObjectStoreKeys } from '../../keys/object.store.keys'; import { ObjectStoreKeys } from '../../keys/object.store.keys';
import { WordNlp } from '../../text/nlp/word.nlp';
import { fnConsoleLog } from '../../fn/console.fn'; import { fnConsoleLog } from '../../fn/console.fn';
export class PinAddCommand implements ICommand<Promise<ObjDto<ObjPagePinDto>>> { export class PinAddCommand implements ICommand<Promise<ObjDto<ObjPagePinDto>>> {
@ -47,10 +48,11 @@ export class PinAddCommand implements ICommand<Promise<ObjDto<ObjPagePinDto>>> {
}, },
encryption: { encryption: {
encrypted: false encrypted: false
}, }
hashtags: []
}; };
await WordNlp.indexFlat(this.pin.snapshot.words, id);
const key = `${ObjectStoreKeys.OBJECT_ID}:${id}`; const key = `${ObjectStoreKeys.OBJECT_ID}:${id}`;
await BrowserStorageWrapper.set(key, dto); await BrowserStorageWrapper.set(key, dto);

@ -19,7 +19,6 @@ import { ICommand } from '../../model/shared/common.dto';
import { LinkHrefOriginStore } from '../../store/link-href-origin.store'; import { LinkHrefOriginStore } from '../../store/link-href-origin.store';
import { ObjDto } from '../../model/obj/obj.dto'; import { ObjDto } from '../../model/obj/obj.dto';
import { ObjPagePinDto } from '../../model/obj/obj-pin.dto'; import { ObjPagePinDto } from '../../model/obj/obj-pin.dto';
import { ObjRemoveHashtagsCommand } from '../obj/hashtag/obj-remove-hashtags.command';
import { ObjRemoveIdCommand } from '../obj/id/obj-remove-id.command'; import { ObjRemoveIdCommand } from '../obj/id/obj-remove-id.command';
import { ObjRemoveSnapshotContentCommand } from '../obj/content/obj-remove-snapshot-content.command'; import { ObjRemoveSnapshotContentCommand } from '../obj/content/obj-remove-snapshot-content.command';
import { ObjectStoreKeys } from '../../keys/object.store.keys'; import { ObjectStoreKeys } from '../../keys/object.store.keys';
@ -34,8 +33,6 @@ export class PinRemoveCommand implements ICommand<void> {
await new ObjRemoveIdCommand(this.obj.id, new Date(this.obj.createdAt)).execute(); await new ObjRemoveIdCommand(this.obj.id, new Date(this.obj.createdAt)).execute();
await new ObjRemoveHashtagsCommand(this.obj.id, this.obj.hashtags).execute(); await new ObjRemoveSnapshotContentCommand(this.obj.data.snapshot, this.obj.id).execute();
await new ObjRemoveSnapshotContentCommand(this.obj.data.snapshot).execute();
} }
} }

@ -22,7 +22,7 @@ import { environmentConfig } from '../../../environment';
export class TokenStorageGetCommand implements ICommand<Promise<AccessTokenDto | undefined>> { export class TokenStorageGetCommand implements ICommand<Promise<AccessTokenDto | undefined>> {
async execute(): Promise<AccessTokenDto | undefined> { async execute(): Promise<AccessTokenDto | undefined> {
const key = `${ObjectStoreKeys.ACCESS_TOKEN}:${environmentConfig.url.api}`; const key = `${ObjectStoreKeys.ACCESS_TOKEN}:${environmentConfig.defaultServer}`;
return await BrowserStorageWrapper.get<AccessTokenDto | undefined>(key); return await BrowserStorageWrapper.get<AccessTokenDto | undefined>(key);
} }
} }

@ -21,7 +21,7 @@ import { environmentConfig } from '../../../environment';
export class TokenStorageRemoveCommand implements ICommand<Promise<void>> { export class TokenStorageRemoveCommand implements ICommand<Promise<void>> {
async execute(): Promise<void> { async execute(): Promise<void> {
const key = `${ObjectStoreKeys.ACCESS_TOKEN}:${environmentConfig.url.api}`; const key = `${ObjectStoreKeys.ACCESS_TOKEN}:${environmentConfig.defaultServer}`;
await BrowserStorageWrapper.remove(key); await BrowserStorageWrapper.remove(key);
} }
} }

@ -23,7 +23,7 @@ import { environmentConfig } from '../../../environment';
export class TokenStorageSetCommand implements ICommand<Promise<void>> { export class TokenStorageSetCommand implements ICommand<Promise<void>> {
constructor(private value: AccessTokenDto) {} constructor(private value: AccessTokenDto) {}
async execute(): Promise<void> { async execute(): Promise<void> {
const key = `${ObjectStoreKeys.ACCESS_TOKEN}:${environmentConfig.url.api}`; const key = `${ObjectStoreKeys.ACCESS_TOKEN}:${environmentConfig.defaultServer}`;
await BrowserStorageWrapper.set(key, this.value); await BrowserStorageWrapper.set(key, this.value);
} }
} }

@ -21,6 +21,7 @@ import { ObjAddIdCommand } from '../obj/id/obj-add-id.command';
import { ObjNextIdCommand } from '../obj/id/obj-next-id.command'; import { ObjNextIdCommand } from '../obj/id/obj-next-id.command';
import { ObjSnapshotDto } from '../../model/obj/obj-snapshot.dto'; import { ObjSnapshotDto } from '../../model/obj/obj-snapshot.dto';
import { ObjectStoreKeys } from '../../keys/object.store.keys'; import { ObjectStoreKeys } from '../../keys/object.store.keys';
import { WordNlp } from '../../text/nlp/word.nlp';
export class PageElementSnapshotAddCommand implements ICommand<Promise<void>> { export class PageElementSnapshotAddCommand implements ICommand<Promise<void>> {
constructor(private dto: ObjSnapshotDto) {} constructor(private dto: ObjSnapshotDto) {}
@ -41,10 +42,11 @@ export class PageElementSnapshotAddCommand implements ICommand<Promise<void>> {
}, },
encryption: { encryption: {
encrypted: false encrypted: false
}, }
hashtags: []
}; };
await WordNlp.indexFlat(this.dto.words, id);
const key = `${ObjectStoreKeys.OBJECT_ID}:${id}`; const key = `${ObjectStoreKeys.OBJECT_ID}:${id}`;
await BrowserStorageWrapper.set(key, dto); await BrowserStorageWrapper.set(key, dto);

@ -18,6 +18,7 @@ import { BrowserStorageWrapper } from '../../service/browser.storage.wrapper';
import { ICommand } from '../../model/shared/common.dto'; import { ICommand } from '../../model/shared/common.dto';
import { ObjDto } from '../../model/obj/obj.dto'; import { ObjDto } from '../../model/obj/obj.dto';
import { ObjRemoveIdCommand } from '../obj/id/obj-remove-id.command'; import { ObjRemoveIdCommand } from '../obj/id/obj-remove-id.command';
import { ObjRemoveSnapshotContentCommand } from '../obj/content/obj-remove-snapshot-content.command';
import { ObjSnapshotDto } from '../../model/obj/obj-snapshot.dto'; import { ObjSnapshotDto } from '../../model/obj/obj-snapshot.dto';
import { ObjectStoreKeys } from '../../keys/object.store.keys'; import { ObjectStoreKeys } from '../../keys/object.store.keys';
@ -29,5 +30,7 @@ export class PageElementSnapshotRemoveCommand implements ICommand<Promise<void>>
await BrowserStorageWrapper.remove(key); await BrowserStorageWrapper.remove(key);
await new ObjRemoveIdCommand(this.obj.id, new Date(this.obj.createdAt)).execute(); await new ObjRemoveIdCommand(this.obj.id, new Date(this.obj.createdAt)).execute();
await new ObjRemoveSnapshotContentCommand(this.obj.data, this.obj.id).execute();
} }
} }

@ -21,6 +21,7 @@ import { ObjAddIdCommand } from '../obj/id/obj-add-id.command';
import { ObjNextIdCommand } from '../obj/id/obj-next-id.command'; import { ObjNextIdCommand } from '../obj/id/obj-next-id.command';
import { ObjSnapshotDto } from '../../model/obj/obj-snapshot.dto'; import { ObjSnapshotDto } from '../../model/obj/obj-snapshot.dto';
import { ObjectStoreKeys } from '../../keys/object.store.keys'; import { ObjectStoreKeys } from '../../keys/object.store.keys';
import { WordNlp } from '../../text/nlp/word.nlp';
export class PageSnapshotAddCommand implements ICommand<Promise<void>> { export class PageSnapshotAddCommand implements ICommand<Promise<void>> {
constructor(private dto: ObjSnapshotDto) {} constructor(private dto: ObjSnapshotDto) {}
@ -41,9 +42,9 @@ export class PageSnapshotAddCommand implements ICommand<Promise<void>> {
}, },
encryption: { encryption: {
encrypted: false encrypted: false
}, }
hashtags: []
}; };
await WordNlp.indexFlat(this.dto.words, id);
const key = `${ObjectStoreKeys.OBJECT_ID}:${id}`; const key = `${ObjectStoreKeys.OBJECT_ID}:${id}`;
await BrowserStorageWrapper.set(key, dto); await BrowserStorageWrapper.set(key, dto);

@ -31,6 +31,6 @@ export class PageSnapshotRemoveCommand implements ICommand<Promise<void>> {
await new ObjRemoveIdCommand(this.obj.id, new Date(this.obj.createdAt)).execute(); await new ObjRemoveIdCommand(this.obj.id, new Date(this.obj.createdAt)).execute();
await new ObjRemoveSnapshotContentCommand(this.obj.data).execute(); await new ObjRemoveSnapshotContentCommand(this.obj.data, this.obj.id).execute();
} }
} }

@ -28,15 +28,9 @@ export interface SettingsConfig {
videoDisplayTime: number; videoDisplayTime: number;
} }
export interface UrlConfig {
short: string;
web: string;
api: string;
}
interface EnvironmentConfig { interface EnvironmentConfig {
showAckMessage: boolean; showAckMessage: boolean;
url: UrlConfig; defaultServer: string;
isProduction: boolean; isProduction: boolean;
settings: SettingsConfig; settings: SettingsConfig;
objListLimit: number; objListLimit: number;
@ -44,11 +38,7 @@ interface EnvironmentConfig {
export const environmentConfig: EnvironmentConfig = { export const environmentConfig: EnvironmentConfig = {
showAckMessage: false, showAckMessage: false,
url: { defaultServer: process.env.WEB_URL || 'https://pinmenote.com',
api: process.env.API_URL || 'https://pinmenote.com',
web: process.env.WEB_URL || 'https://pinmenote.com',
short: process.env.SHORT_URL || 'https://pmn.cl'
},
isProduction: process.env.IS_PRODUCTION === 'true', isProduction: process.env.IS_PRODUCTION === 'true',
settings: { settings: {
version: parseInt(process.env.VERSION || '1'), version: parseInt(process.env.VERSION || '1'),

@ -33,10 +33,14 @@ export class ObjectStoreKeys {
static readonly OBJECT_LINK = 'o:link'; static readonly OBJECT_LINK = 'o:link';
// INDEX // INDEX
static readonly SEARCH_INDEX = 'i'; static readonly SEARCH_INDEX = 's:i';
static readonly SEARCH_WORD = 's:w';
static readonly ACCESS_TOKEN = 'accessToken'; static readonly ACCESS_TOKEN = 'accessToken';
// SYNC // SYNC
static readonly SYNC_TIME = 'sync'; static readonly SYNC_TIME = 'sync';
// SETTINGS
static readonly CONTENT_SETTINGS_KEY = 'content-settings';
} }

@ -1,19 +0,0 @@
/*
* This file is part of the pinmenote-extension distribution (https://github.com/pinmenote/pinmenote-extension).
* Copyright (c) 2022 Michal Szczepanski.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
export class SettingsKeys {
static readonly CONTENT_SETTINGS_KEY = 'content-settings';
}

@ -27,6 +27,8 @@ export interface ObjCanvasDto {
export interface ObjSnapshotDto { export interface ObjSnapshotDto {
url: ObjUrlDto; url: ObjUrlDto;
title: string; title: string;
words: string[];
hashtags: string[];
screenshot?: string; screenshot?: string;
contentId: number; contentId: number;
canvas?: ObjCanvasDto; canvas?: ObjCanvasDto;

@ -55,6 +55,5 @@ export interface ObjDto<T = ObjDataDto> {
createdAt: number; createdAt: number;
local: ObjLocalDto; local: ObjLocalDto;
encryption: ObjEncryptionDto; encryption: ObjEncryptionDto;
hashtags: string[];
data: T; data: T;
} }

@ -15,13 +15,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import * as LanguageDetect from 'languagedetect'; import * as LanguageDetect from 'languagedetect';
import { fnConsoleLog } from '../fn/console.fn';
export class DetectLanguage { export class DetectLanguage {
private static lang = new LanguageDetect(); private static lang = new LanguageDetect();
static detect(sample: string): string { static detect(sample: string): string {
this.lang.setLanguageType('iso2'); this.lang.setLanguageType('iso2');
const languages = this.lang.detect(sample); const samp = sample.length < 1000 ? sample : sample.substring(0, 1000);
const languages = this.lang.detect(samp);
fnConsoleLog('DetectLanguage', languages[0]);
return languages[0][0]; return languages[0][0];
} }
} }

@ -53,13 +53,53 @@ export class WordNlp {
} }
await this.saveStorage(flatPart, id); await this.saveStorage(flatPart, id);
flatPart = ''; flatPart = '';
await this.saveWord(word);
} }
fnConsoleLog('indexed', Array.from(this.flatSet), 'count', this.flatSet.size, 'in', Date.now() - a); fnConsoleLog('indexed', Array.from(this.flatSet), 'count', this.flatSet.size, 'in', Date.now() - a);
}; };
static removeFlat = async (words: string[], id: number): Promise<void> => {
const a = Date.now();
let ch = '';
let flatPart = '';
for (const word of words) {
for (let i = 0; i < word.length; i++) {
ch = word.charAt(i).toLowerCase();
flatPart += ch;
if (flatPart.length % 2 === 0) {
await this.removeStorage(flatPart, id);
}
}
await this.removeStorage(flatPart, id);
flatPart = '';
}
fnConsoleLog('removed', Array.from(this.flatSet), 'count', this.flatSet.size, 'in', Date.now() - a);
};
private static removeStorage = async (value: string, id: number) => {
if (this.flatSet.has(value)) return;
this.flatSet.add(value);
const key = `${ObjectStoreKeys.SEARCH_INDEX}:${value}`;
const arr = await BrowserStorageWrapper.get<number[]>(key);
if (!arr) return;
const idx = arr.indexOf(id);
if (idx === -1) return;
arr.splice(idx, 1);
if (arr.length === 0) {
await BrowserStorageWrapper.remove(key);
await this.removeWord(value);
} else {
await BrowserStorageWrapper.set<number[]>(key, arr);
}
};
private static saveStorage = async (value: string, id: number) => { private static saveStorage = async (value: string, id: number) => {
// skip existing // skip existing
if (this.flatSet.has(value)) return; if (this.flatSet.has(value)) return;
this.flatSet.add(value);
const key = `${ObjectStoreKeys.SEARCH_INDEX}:${value}`; const key = `${ObjectStoreKeys.SEARCH_INDEX}:${value}`;
let arr = await BrowserStorageWrapper.get<number[]>(key); let arr = await BrowserStorageWrapper.get<number[]>(key);
@ -69,6 +109,36 @@ export class WordNlp {
arr = [id]; arr = [id];
} }
await BrowserStorageWrapper.set<number[]>(key, arr); await BrowserStorageWrapper.set<number[]>(key, arr);
this.flatSet.add(value); };
private static saveWord = async (word: string) => {
if (word.length < 3) return;
const start = word.substring(0, 2);
const key = `${ObjectStoreKeys.SEARCH_WORD}:${start}`;
let arr = await BrowserStorageWrapper.get<string[]>(key);
if (arr) {
const idx = arr.indexOf(word);
if (idx === -1) arr.push(word);
} else {
arr = [word];
}
await BrowserStorageWrapper.set<string[]>(key, arr);
};
private static removeWord = async (word: string) => {
const start = word.substring(0, 2);
const key = `${ObjectStoreKeys.SEARCH_WORD}:${start}`;
const arr = await BrowserStorageWrapper.get<string[]>(key);
if (!arr) return;
const idx = arr.indexOf(word);
if (idx === -1) return;
arr.splice(idx, 1);
if (arr.length === 0) {
await BrowserStorageWrapper.remove(key);
} else {
await BrowserStorageWrapper.set<string[]>(key, arr);
}
}; };
} }

@ -33,13 +33,15 @@ export class ContentPageSnapshotAddCommand implements ICommand<Promise<void>> {
} }
const screenshot = await ScreenshotFactory.takeScreenshot(undefined, this.url); const screenshot = await ScreenshotFactory.takeScreenshot(undefined, this.url);
const contentId = await new SnapshotContentSaveCommand(document.body).execute(); const res = await new SnapshotContentSaveCommand(document.body).execute();
const dto: ObjSnapshotDto = { const dto: ObjSnapshotDto = {
title: document.title, title: document.title,
url: this.url, url: this.url,
screenshot, screenshot,
contentId contentId: res.id,
words: res.words,
hashtags: []
}; };
await new PageSnapshotAddCommand(dto).execute(); await new PageSnapshotAddCommand(dto).execute();

@ -22,12 +22,16 @@ import { ICommand } from '../../../common/model/shared/common.dto';
import { ObjNextContentIdCommand } from '../../../common/command/obj/content/obj-next-content-id.command'; import { ObjNextContentIdCommand } from '../../../common/command/obj/content/obj-next-content-id.command';
import { ObjSnapshotContentDto } from '../../../common/model/obj/obj-snapshot.dto'; import { ObjSnapshotContentDto } from '../../../common/model/obj/obj-snapshot.dto';
import { ObjectStoreKeys } from '../../../common/keys/object.store.keys'; import { ObjectStoreKeys } from '../../../common/keys/object.store.keys';
import { WordNlp } from '../../../common/text/nlp/word.nlp';
import { fnConsoleLog } from '../../../common/fn/console.fn'; import { fnConsoleLog } from '../../../common/fn/console.fn';
export class SnapshotContentSaveCommand implements ICommand<Promise<number>> { interface SnapshotResult {
id: number;
words: string[];
}
export class SnapshotContentSaveCommand implements ICommand<Promise<SnapshotResult>> {
constructor(private element: HTMLElement) {} constructor(private element: HTMLElement) {}
async execute(): Promise<number> { async execute(): Promise<SnapshotResult> {
const id = await new ObjNextContentIdCommand().execute(); const id = await new ObjNextContentIdCommand().execute();
const key = `${ObjectStoreKeys.CONTENT_ID}:${id}`; const key = `${ObjectStoreKeys.CONTENT_ID}:${id}`;
@ -39,9 +43,8 @@ export class SnapshotContentSaveCommand implements ICommand<Promise<number>> {
fnConsoleLog('HTML DONE'); fnConsoleLog('HTML DONE');
const css = await CssFactory.computeCssContent(urlCache); const css = await CssFactory.computeCssContent(urlCache);
fnConsoleLog('CSS DONE'); fnConsoleLog('CSS DONE');
const tagList = AutoTagMediator.computeTags(this.element); const words = AutoTagMediator.computeTags(this.element);
fnConsoleLog('SOCIAL TAGS DONE'); fnConsoleLog('SOCIAL TAGS DONE');
await WordNlp.indexFlat(tagList, id);
fnConsoleLog('SKIPPED', urlCache); fnConsoleLog('SKIPPED', urlCache);
fnConsoleLog('END'); fnConsoleLog('END');
@ -54,6 +57,6 @@ export class SnapshotContentSaveCommand implements ICommand<Promise<number>> {
content: htmlContent.content content: htmlContent.content
}); });
return id; return { id, words };
} }
} }

@ -28,12 +28,17 @@ export class SnapshotCreateCommand implements ICommand<Promise<ObjSnapshotDto>>
const rect = this.canvas ? this.canvas.rect : XpathFactory.computeRect(this.element); const rect = this.canvas ? this.canvas.rect : XpathFactory.computeRect(this.element);
const screenshot = await ScreenshotFactory.takeScreenshot(rect, this.url); const screenshot = await ScreenshotFactory.takeScreenshot(rect, this.url);
let contentId = -1; let contentId = -1;
let words: string[] = [];
if (!this.canvas) { if (!this.canvas) {
contentId = await new SnapshotContentSaveCommand(this.element).execute(); const res = await new SnapshotContentSaveCommand(this.element).execute();
contentId = res.id;
words = res.words;
} }
return { return {
title: document.title, title: document.title,
url: this.url, url: this.url,
words,
hashtags: [],
canvas: this.canvas, canvas: this.canvas,
screenshot, screenshot,
contentId contentId

@ -68,10 +68,11 @@ export class HtmlFactory {
skipUrlCache?: Set<string> skipUrlCache?: Set<string>
): Promise<HtmlIntermediateData> => { ): Promise<HtmlIntermediateData> => {
if (!skipTagCache) skipTagCache = new Set<string>(); if (!skipTagCache) skipTagCache = new Set<string>();
const tagName = ref.tagName.toLowerCase(); const tagName = ref.tagName.toLowerCase();
if (!HtmlConstraints.KNOWN_ELEMENTS.includes(tagName) && !skipTagCache.has(tagName)) { if (!HtmlConstraints.KNOWN_ELEMENTS.includes(tagName) && !skipTagCache.has(tagName)) {
const shadow = BrowserApi.shadowRoot(ref); const shadow = BrowserApi.shadowRoot(ref);
// fnConsoleLog('NOT KNOWN ELEMENT', tagName, 'SHADOW', shadow);
// Go with shadow // Go with shadow
if (shadow) { if (shadow) {
return ShadowFactory.computeShadow(tagName, ref, shadow, skipUrlCache); return ShadowFactory.computeShadow(tagName, ref, shadow, skipUrlCache);
@ -79,6 +80,7 @@ export class HtmlFactory {
skipTagCache.add(tagName); skipTagCache.add(tagName);
} }
} }
let html = `<${tagName} `; let html = `<${tagName} `;
const video: ObjVideoDataDto[] = []; const video: ObjVideoDataDto[] = [];
const content: ObjContentDto[] = []; const content: ObjContentDto[] = [];
@ -168,11 +170,26 @@ export class HtmlFactory {
skipUrlCache?: Set<string> skipUrlCache?: Set<string>
): Promise<HtmlIntermediateData> => { ): Promise<HtmlIntermediateData> => {
if (!ref.firstElementChild) return HtmlAttrFactory.EMPTY_RESULT; if (!ref.firstElementChild) return HtmlAttrFactory.EMPTY_RESULT;
const children = Array.from(ref.children);
const images = children.filter((c) => c.tagName.toLowerCase() === 'img');
const sources = children.filter((c) => c.tagName.toLowerCase() === 'source');
const isSource = sources.length > 0;
const content: ObjContentDto[] = []; const content: ObjContentDto[] = [];
let html = `<picture `; let html = `<picture `;
html += await HtmlAttrFactory.computeAttrValues('picture', Array.from(ref.attributes)); const attrs = Array.from(ref.attributes);
html = html.substring(0, html.length - 1) + '>'; if (isSource && attrs.filter((attr) => attr.nodeName === 'style').length === 0) {
const child = ref.firstElementChild; const rect = ref.getBoundingClientRect();
html += ` style="width:${rect.width}px;height:${rect.height}px" `;
}
html += await HtmlAttrFactory.computeAttrValues('picture', attrs);
html = html.substring(0, html.length - 1);
// Source must be converted to img - we lose size information that's why we need to put style with those attributes
html += '>';
const child = sources.length > 0 ? sources[0] : images[0];
const childTag = child.tagName.toLowerCase(); const childTag = child.tagName.toLowerCase();
const value = await HtmlImgFactory.computeImgValue(child as HTMLImageElement, skipUrlCache); const value = await HtmlImgFactory.computeImgValue(child as HTMLImageElement, skipUrlCache);
const uid = fnUid(); const uid = fnUid();

@ -33,11 +33,28 @@ export class ShadowFactory {
shadow: ShadowRoot, shadow: ShadowRoot,
skipUrlCache?: Set<string> skipUrlCache?: Set<string>
): Promise<HtmlIntermediateData> => { ): Promise<HtmlIntermediateData> => {
fnConsoleLog('COMPUTE SHADOW !!!'); fnConsoleLog('COMPUTE SHADOW !!!', tagName, ref);
const uid = fnUid(); const uid = fnUid();
let html = `<${tagName} data-pin-id="${uid}" `; let html = `<${tagName} data-pin-id="${uid}" `;
html += await HtmlAttrFactory.computeAttrValues(tagName, Array.from(ref.attributes)); html += await HtmlAttrFactory.computeAttrValues(tagName, Array.from(ref.attributes));
html = html.substring(0, html.length - 1) + '>'; html = html.substring(0, html.length - 1) + '>';
const nodes = Array.from(ref.childNodes);
for (const node of nodes) {
if (node.nodeType === Node.TEXT_NODE) {
const nre = new RegExp(String.fromCharCode(160), 'g');
let txt = node.textContent ? node.textContent.replace(nre, '&nbsp;') : '';
txt = txt.replace('<', '&lt').replace('>', '&gt;');
html += txt;
} else if (node.nodeType === Node.ELEMENT_NODE) {
html += await this.computeShadowChild(node as Element);
} else if (node.nodeType === Node.COMMENT_NODE) {
html += '<!---->';
} else {
fnConsoleLog('PROBLEM fnComputeHtmlContent !!!', node.nodeType);
}
}
html += `</${tagName}>`; html += `</${tagName}>`;
const shadowHtml = await this.computeShadowHtml(shadow, skipUrlCache); const shadowHtml = await this.computeShadowHtml(shadow, skipUrlCache);
return { return {
@ -77,6 +94,11 @@ export class ShadowFactory {
private static computeShadowChild = async (ref: Element, skipUrlCache?: Set<string>): Promise<string> => { private static computeShadowChild = async (ref: Element, skipUrlCache?: Set<string>): Promise<string> => {
const tagName = ref.tagName.toLowerCase(); const tagName = ref.tagName.toLowerCase();
let htmlPrefilled = false;
let html = `<${tagName} `;
if (tagName === 'link') { if (tagName === 'link') {
const uri = ref.getAttribute('href'); const uri = ref.getAttribute('href');
if (uri) { if (uri) {
@ -96,22 +118,23 @@ export class ShadowFactory {
return pic.html; return pic.html;
} else if (!HtmlConstraints.KNOWN_ELEMENTS.includes(tagName)) { } else if (!HtmlConstraints.KNOWN_ELEMENTS.includes(tagName)) {
const shadow = BrowserApi.shadowRoot(ref); const shadow = BrowserApi.shadowRoot(ref);
if (shadow) { if (shadow) {
let html = `<${tagName} `;
html += await HtmlAttrFactory.computeAttrValues(tagName, Array.from(ref.attributes)); html += await HtmlAttrFactory.computeAttrValues(tagName, Array.from(ref.attributes));
html = html.substring(0, html.length - 1) + '>'; html = html.substring(0, html.length - 1) + '>';
html += await this.computeShadowHtml(shadow, skipUrlCache); html += await this.computeShadowHtml(shadow, skipUrlCache);
html += `</${tagName}>`; htmlPrefilled = true;
return html;
} }
} }
let html = `<${tagName} `;
html += await HtmlAttrFactory.computeAttrValues(tagName, Array.from(ref.attributes)); if (!htmlPrefilled) {
if (tagName === 'img') { html += await HtmlAttrFactory.computeAttrValues(tagName, Array.from(ref.attributes));
const value = await HtmlImgFactory.computeImgValue(ref as HTMLImageElement, skipUrlCache); if (tagName === 'img') {
html += `src="${value}" `; const value = await HtmlImgFactory.computeImgValue(ref as HTMLImageElement, skipUrlCache);
html += `src="${value}" `;
}
html = html.substring(0, html.length - 1) + '>';
} }
html = html.substring(0, html.length - 1) + '>';
const nodes = Array.from(ref.childNodes); const nodes = Array.from(ref.childNodes);
for (const node of nodes) { for (const node of nodes) {

@ -16,7 +16,7 @@
*/ */
import { SettingsConfig, environmentConfig } from '../../common/environment'; import { SettingsConfig, environmentConfig } from '../../common/environment';
import { BrowserStorageWrapper } from '../../common/service/browser.storage.wrapper'; import { BrowserStorageWrapper } from '../../common/service/browser.storage.wrapper';
import { SettingsKeys } from '../../common/keys/settings.keys'; import { ObjectStoreKeys } from '../../common/keys/object.store.keys';
export class ContentSettingsStore { export class ContentSettingsStore {
private static settings: SettingsConfig; private static settings: SettingsConfig;
@ -43,6 +43,6 @@ export class ContentSettingsStore {
} }
static initSettings = async (): Promise<void> => { static initSettings = async (): Promise<void> => {
this.settings = await BrowserStorageWrapper.get<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY); this.settings = await BrowserStorageWrapper.get<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY);
}; };
} }

@ -38,7 +38,7 @@ const inputContainerStyle = {
}; };
function getWebsiteUrl(uri: string): string { function getWebsiteUrl(uri: string): string {
return `${environmentConfig.url.web}${uri}`; return `${environmentConfig.defaultServer}${uri}`;
} }
interface LoginComponentProps { interface LoginComponentProps {

@ -38,7 +38,7 @@ const inputContainerStyle = {
}; };
function getWebsiteUrl(uri: string): string { function getWebsiteUrl(uri: string): string {
return `${environmentConfig.url.web}${uri}`; return `${environmentConfig.defaultServer}${uri}`;
} }
interface Verify2faComponentProps { interface Verify2faComponentProps {

@ -34,7 +34,7 @@ import { fnUid } from '../common/fn/uid.fn';
* this prevents crashing extension on some web pages with infinite iframe loop (thank you fb) * this prevents crashing extension on some web pages with infinite iframe loop (thank you fb)
*/ */
export class IframeScript { export class IframeScript {
private href: string; private readonly href: string;
private timeoutId = 0; private timeoutId = 0;
private type?: ObjTypeDto; private type?: ObjTypeDto;
private uid?: string; private uid?: string;
@ -45,8 +45,6 @@ export class IframeScript {
ContentMessageHandler.start(this.href); ContentMessageHandler.start(this.href);
fnConsoleLog('IframeScript->constructor', this.href, window.top);
document.addEventListener('visibilitychange', this.handleVisibilityChange); document.addEventListener('visibilitychange', this.handleVisibilityChange);
TinyEventDispatcher.addListener<number[]>(BusMessageType.CNT_SETTINGS, this.handlePinSettings); TinyEventDispatcher.addListener<number[]>(BusMessageType.CNT_SETTINGS, this.handlePinSettings);

@ -206,7 +206,7 @@ export const HtmlPreviewComponent: FunctionComponent = () => {
}; };
const renderShadow = (el: Element, content: ObjShadowContentDto) => { const renderShadow = (el: Element, content: ObjShadowContentDto) => {
el.innerHTML = content.html; el.innerHTML = content.html + el.innerHTML;
renderTemplate(el); renderTemplate(el);
}; };

@ -18,8 +18,8 @@ import React, { CSSProperties, ChangeEvent, FunctionComponent, useEffect, useSta
import { BrowserStorageWrapper } from '../../../../common/service/browser.storage.wrapper'; import { BrowserStorageWrapper } from '../../../../common/service/browser.storage.wrapper';
import { DEFAULT_BORDER_RADIUS } from '../../../../common/components/colors'; import { DEFAULT_BORDER_RADIUS } from '../../../../common/components/colors';
import Input from '@mui/material/Input'; import Input from '@mui/material/Input';
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
import { SettingsConfig } from '../../../../common/environment'; import { SettingsConfig } from '../../../../common/environment';
import { SettingsKeys } from '../../../../common/keys/settings.keys';
import { SettingsStore } from '../../../store/settings.store'; import { SettingsStore } from '../../../store/settings.store';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
@ -45,14 +45,14 @@ export const ContentSettingsComponent: FunctionComponent = () => {
if (!SettingsStore.settings) return; if (!SettingsStore.settings) return;
setBorderRadius(e.target.value); setBorderRadius(e.target.value);
SettingsStore.settings.borderRadius = e.target.value; SettingsStore.settings.borderRadius = e.target.value;
await BrowserStorageWrapper.set<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY, SettingsStore.settings); await BrowserStorageWrapper.set<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY, SettingsStore.settings);
}; };
const handleBorderStyleChange = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => { const handleBorderStyleChange = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => {
if (!SettingsStore.settings) return; if (!SettingsStore.settings) return;
setBorderStyle(e.target.value); setBorderStyle(e.target.value);
SettingsStore.settings.borderStyle = e.target.value; SettingsStore.settings.borderStyle = e.target.value;
await BrowserStorageWrapper.set<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY, SettingsStore.settings); await BrowserStorageWrapper.set<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY, SettingsStore.settings);
}; };
return ( return (

@ -19,9 +19,9 @@ import { ScreenshotFormat, SettingsConfig } from '../../../../common/environment
import { BrowserStorageWrapper } from '../../../../common/service/browser.storage.wrapper'; import { BrowserStorageWrapper } from '../../../../common/service/browser.storage.wrapper';
import Input from '@mui/material/Input'; import Input from '@mui/material/Input';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import { ObjectStoreKeys } from '../../../../common/keys/object.store.keys';
import Select from '@mui/material/Select'; import Select from '@mui/material/Select';
import { SelectChangeEvent } from '@mui/material/Select'; import { SelectChangeEvent } from '@mui/material/Select';
import { SettingsKeys } from '../../../../common/keys/settings.keys';
import { SettingsStore } from '../../../store/settings.store'; import { SettingsStore } from '../../../store/settings.store';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
@ -49,7 +49,7 @@ export const ScreenshotSettingsComponent: FunctionComponent = () => {
setScreenshotQuality(value); setScreenshotQuality(value);
if (value > 0 && value <= 100) { if (value > 0 && value <= 100) {
SettingsStore.settings.screenshotQuality = value; SettingsStore.settings.screenshotQuality = value;
await BrowserStorageWrapper.set<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY, SettingsStore.settings); await BrowserStorageWrapper.set<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY, SettingsStore.settings);
} }
}; };
@ -57,7 +57,7 @@ export const ScreenshotSettingsComponent: FunctionComponent = () => {
if (!SettingsStore.settings) return; if (!SettingsStore.settings) return;
setScreenshotFormat(e.target.value); setScreenshotFormat(e.target.value);
SettingsStore.settings.screenshotFormat = e.target.value as ScreenshotFormat; SettingsStore.settings.screenshotFormat = e.target.value as ScreenshotFormat;
await BrowserStorageWrapper.set<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY, SettingsStore.settings); await BrowserStorageWrapper.set<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY, SettingsStore.settings);
}; };
return ( return (

@ -15,13 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { BrowserStorageWrapper } from '../../common/service/browser.storage.wrapper'; import { BrowserStorageWrapper } from '../../common/service/browser.storage.wrapper';
import { ObjectStoreKeys } from '../../common/keys/object.store.keys';
import { SettingsConfig } from '../../common/environment'; import { SettingsConfig } from '../../common/environment';
import { SettingsKeys } from '../../common/keys/settings.keys';
export class SettingsStore { export class SettingsStore {
static settings?: SettingsConfig; static settings?: SettingsConfig;
static fetchData = async (): Promise<void> => { static fetchData = async (): Promise<void> => {
this.settings = await BrowserStorageWrapper.get<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY); this.settings = await BrowserStorageWrapper.get<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY);
}; };
} }

@ -30,7 +30,7 @@ export class ApiHelper {
} }
static get apiUrl(): string { static get apiUrl(): string {
return environmentConfig.url.api; return environmentConfig.defaultServer;
} }
static async getStoreUrl(): Promise<string> { static async getStoreUrl(): Promise<string> {

@ -18,8 +18,8 @@ import { BrowserApi } from '../../../common/service/browser.api.wrapper';
import { BrowserStorageWrapper } from '../../../common/service/browser.storage.wrapper'; import { BrowserStorageWrapper } from '../../../common/service/browser.storage.wrapper';
import { BusMessageType } from '../../../common/model/bus.model'; import { BusMessageType } from '../../../common/model/bus.model';
import { ICommand } from '../../../common/model/shared/common.dto'; import { ICommand } from '../../../common/model/shared/common.dto';
import { ObjectStoreKeys } from '../../../common/keys/object.store.keys';
import { SettingsConfig } from '../../../common/environment'; import { SettingsConfig } from '../../../common/environment';
import { SettingsKeys } from '../../../common/keys/settings.keys';
import { fnConsoleLog } from '../../../common/fn/console.fn'; import { fnConsoleLog } from '../../../common/fn/console.fn';
export class ContentTakeScreenshotCommand implements ICommand<void> { export class ContentTakeScreenshotCommand implements ICommand<void> {
@ -27,7 +27,7 @@ export class ContentTakeScreenshotCommand implements ICommand<void> {
async execute(): Promise<void> { async execute(): Promise<void> {
try { try {
fnConsoleLog('ContentTakeScreenshotCommand->execute', this.url); fnConsoleLog('ContentTakeScreenshotCommand->execute', this.url);
const settings = await BrowserStorageWrapper.get<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY); const settings = await BrowserStorageWrapper.get<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY);
const data = await BrowserApi.tabs.captureVisibleTab({ const data = await BrowserApi.tabs.captureVisibleTab({
format: settings.screenshotFormat, format: settings.screenshotFormat,
quality: settings.screenshotQuality quality: settings.screenshotQuality

@ -18,12 +18,12 @@ import { BrowserApi } from '../../../common/service/browser.api.wrapper';
import { BrowserStorageWrapper } from '../../../common/service/browser.storage.wrapper'; import { BrowserStorageWrapper } from '../../../common/service/browser.storage.wrapper';
import { BusMessageType } from '../../../common/model/bus.model'; import { BusMessageType } from '../../../common/model/bus.model';
import { ICommand } from '../../../common/model/shared/common.dto'; import { ICommand } from '../../../common/model/shared/common.dto';
import { ObjectStoreKeys } from '../../../common/keys/object.store.keys';
import { SettingsConfig } from '../../../common/environment'; import { SettingsConfig } from '../../../common/environment';
import { SettingsKeys } from '../../../common/keys/settings.keys';
export class PopupTakeScreenshotCommand implements ICommand<Promise<void>> { export class PopupTakeScreenshotCommand implements ICommand<Promise<void>> {
async execute(): Promise<void> { async execute(): Promise<void> {
const settings = await BrowserStorageWrapper.get<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY); const settings = await BrowserStorageWrapper.get<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY);
const data = await BrowserApi.tabs.captureVisibleTab({ const data = await BrowserApi.tabs.captureVisibleTab({
format: settings.screenshotFormat, format: settings.screenshotFormat,
quality: settings.screenshotQuality quality: settings.screenshotQuality

@ -18,15 +18,15 @@ import { SettingsConfig, environmentConfig } from '../../../common/environment';
import { BrowserStorageWrapper } from '../../../common/service/browser.storage.wrapper'; import { BrowserStorageWrapper } from '../../../common/service/browser.storage.wrapper';
import { CryptoGenerateKeyPairCommand } from '../../../common/command/crypto/crypto-generate-key-pair.command'; import { CryptoGenerateKeyPairCommand } from '../../../common/command/crypto/crypto-generate-key-pair.command';
import { ICommand } from '../../../common/model/shared/common.dto'; import { ICommand } from '../../../common/model/shared/common.dto';
import { SettingsKeys } from '../../../common/keys/settings.keys'; import { ObjectStoreKeys } from '../../../common/keys/object.store.keys';
import { fnConsoleLog } from '../../../common/fn/console.fn'; import { fnConsoleLog } from '../../../common/fn/console.fn';
export class SwInitSettingsCommand implements ICommand<Promise<void>> { export class SwInitSettingsCommand implements ICommand<Promise<void>> {
async execute(): Promise<void> { async execute(): Promise<void> {
const settings = await BrowserStorageWrapper.get<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY); const settings = await BrowserStorageWrapper.get<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY);
if (!settings) { if (!settings) {
fnConsoleLog('Settings Initialize'); fnConsoleLog('Settings Initialize');
await BrowserStorageWrapper.set<SettingsConfig>(SettingsKeys.CONTENT_SETTINGS_KEY, environmentConfig.settings); await BrowserStorageWrapper.set<SettingsConfig>(ObjectStoreKeys.CONTENT_SETTINGS_KEY, environmentConfig.settings);
await new CryptoGenerateKeyPairCommand().execute(); await new CryptoGenerateKeyPairCommand().execute();
} else if (settings.version !== environmentConfig.settings.version) { } else if (settings.version !== environmentConfig.settings.version) {
fnConsoleLog('Settings Migrate placeholder'); fnConsoleLog('Settings Migrate placeholder');