Skip to content
This repository has been archived by the owner on Sep 26, 2024. It is now read-only.

Commit

Permalink
Cu 86b0wgnjh Seek and Replace and Highlight (#61)
Browse files Browse the repository at this point in the history
* Add utility for universal text replacement

* wip highlight changed texts

* Finished highlight changed dom text, now storing is missing

* run lint

* changed way we save changes in Local storage and backend

* changed way we save changes in Local storage and backend

* run lint

* merged with main

* run lint

* integrated the universal replacer with the textarea and the highlighter

* run lint

* run lint

* code refactor a bit

* run lint

* code refactor a bit

* run lint

* fixing loading changes from backend

* run lint

* code review changes

* run lint

* code review changes

* run lint

* fixed ts error

* removed ts-ignore

* lint

* prevent complex query selectors from breaking the app

* fix edit mode, and add sanitization

---------

Co-authored-by: Jonathan Kaplan <[email protected]>
Co-authored-by: elg0nz <[email protected]>
  • Loading branch information
3 people authored Jun 19, 2024
1 parent a062754 commit 625fdde
Show file tree
Hide file tree
Showing 15 changed files with 611 additions and 138 deletions.
51 changes: 42 additions & 9 deletions apps/mocksi-lite/background.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import MocksiRollbar from "./MocksiRollbar";
import { SignupURL, WebSocketURL } from "./consts";
import { STORAGE_KEY, SignupURL, WebSocketURL } from "./consts";
import { apiCall } from "./networking";
import { logout } from "./utils";

export interface Alteration {
selector: string;
Expand Down Expand Up @@ -48,13 +49,17 @@ addEventListener("install", () => {
});

chrome.action.onClicked.addListener((activeTab) => {
const { id: currentTabId } = activeTab;
let { id: currentTabId } = activeTab;
if (currentTabId) {
chrome.debugger.detach({ tabId: currentTabId });
try {
chrome.debugger.detach({ tabId: currentTabId });
} catch (e) {
currentTabId = -1;
}
}

if (currentTabId && currentTabId < 0) {
return false;
return;
}
let activeTabUrl = "";
try {
Expand Down Expand Up @@ -148,10 +153,10 @@ function onAttach(tabId: number) {
}

function debuggerDetachHandler() {
console.log("detach");
requests.clear();
}
function createDemo(body: Record<string, unknown>) {

async function createDemo(body: Record<string, unknown>) {
const defaultBody = {
created_timestamp: new Date(),
updated_timestamp: new Date(),
Expand All @@ -171,8 +176,32 @@ function updateDemo(data: Record<string, unknown>) {
apiCall(`recordings/${id}`, "POST", recording).then(() => getRecordings());
}

async function getEmail() {
const value = await chrome.storage.local.get(STORAGE_KEY);
if (!value) {
window.open(SignupURL);
return;
}

let parsedData: { email: string } | undefined;
const storedData = value[STORAGE_KEY] || "{}";
try {
parsedData = JSON.parse(storedData);
} catch (error) {
console.log("Error parsing data from storage: ", error);
parsedData = undefined;
}
if (parsedData?.email) {
return parsedData.email;
}

MocksiRollbar.log("No email found in storage. Logging out");
logout();
}

async function getRecordings() {
const response = await apiCall("recordings/");
const email = await getEmail();
const response = await apiCall(`recordings/?creator=${email}`);
if (!response || response.length === 0) {
return;
}
Expand Down Expand Up @@ -303,13 +332,17 @@ chrome.runtime.onMessage.addListener(
console.log("Received message:", request);

if (request.message === "createDemo") {
if (!request.body) return false;
if (!request.body) {
return false;
}
createDemo(request.body);
return true;
}

if (request.message === "updateDemo") {
if (!request.body) return false;
if (!request.body) {
return false;
}
updateDemo(request.body);
return true;
}
Expand Down
6 changes: 5 additions & 1 deletion apps/mocksi-lite/biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
"linter": {
"enabled": true,
"rules": {
"recommended": true
"recommended": true,
"style": {
"noUselessElse": "error",
"useBlockStatements": "error"
}
}
},
"files": {
Expand Down
25 changes: 19 additions & 6 deletions apps/mocksi-lite/commands/Command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,32 @@ interface DOMModification {
nextText: string;
}

export const buildQuerySelector = (parentElement: HTMLElement) => {
const { localName, id, className } = parentElement;
export const buildQuerySelector = (
parentElement: HTMLElement,
newValue: string,
) => {
const { localName, id, classList } = parentElement;
let keyToSave = localName;
if (id) {
keyToSave += `#${id}`;
}
if (className) {
keyToSave += `.${className}`;
if (classList.length) {
keyToSave += `.${[...classList].join(".")}`;
}
const elements = document.querySelectorAll(keyToSave);
if (elements.length > 1) {
let elements: NodeListOf<Element>;
try {
elements = document.querySelectorAll(keyToSave);
} catch (e: unknown) {
if (e instanceof Error) {
console.error(`Error querying selector ${keyToSave}: ${e}`);
}
return keyToSave;
}

if (elements.length) {
keyToSave += `[${[...elements].indexOf(parentElement)}]`;
}
keyToSave += `{${newValue}}`;
return keyToSave;
};

Expand Down
1 change: 1 addition & 0 deletions apps/mocksi-lite/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const MOCKSI_USER_ID = "mocksi-userId";
export const MOCKSI_SESSION_ID = "mocksi-sessionId"; // FIXME: Move to an environment variable
export const STORAGE_CHANGE_EVENT = "MOCKSI_STORAGE_CHANGE";
export const MOCKSI_AUTH = "mocksi-auth";
export const MOCKSI_HIGHLIGHTER_ID = "mocksi-highlighter";

export const WebSocketURL = "wss://crowllectordb.onrender.com/ws";
export const API_URL = "https://crowllectordb.onrender.com/api";
Expand Down
23 changes: 17 additions & 6 deletions apps/mocksi-lite/content/ContentApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import {
} from "../consts";
import closeIcon from "../public/close-icon.png";
import mocksiLogo from "../public/mocksi-logo.png";
import { sendMessage, setRootPosition } from "../utils";
import { setRootPosition } from "../utils";
import { setEditorMode } from "./EditMode/editMode";
import { ContentHighlighter } from "./EditMode/highlighter";
import Popup from "./Popup";
import { RecordButton } from "./RecordButton";

Expand All @@ -35,6 +36,7 @@ const recordingLabel = (currentStatus: RecordingState) => {

export default function ContentApp({ isOpen, email }: ContentProps) {
const [isDialogOpen, setIsDialogOpen] = useState(isOpen || false);
const [areChangesHighlighted, setAreChangesHighlighted] = useState(true);
const initialState = localStorage.getItem(
MOCKSI_RECORDING_STATE,
) as RecordingState | null;
Expand All @@ -47,12 +49,16 @@ export default function ContentApp({ isOpen, email }: ContentProps) {
setRootPosition(newState);
};

const handleUpdate = () => {
const id = localStorage.getItem(MOCKSI_RECORDING_ID);
sendMessage("updateDemo", { id });
const onChecked = () => {
setAreChangesHighlighted((prevValue) => {
ContentHighlighter.showHideHighlights(!prevValue);
return !prevValue;
});
};

if (!isDialogOpen) return null;
if (!isDialogOpen) {
return null;
}
if (state === RecordingState.READY || state === RecordingState.CREATE) {
return (
<Popup
Expand Down Expand Up @@ -86,7 +92,12 @@ export default function ContentApp({ isOpen, email }: ContentProps) {
<div className={"flex flex-col gap-2"}>
<TextField variant={"title"}>{recordingLabel(state)}</TextField>
<div className="flex gap-2 items-center">
<input type="checkbox" className="h-5 w-5 !rounded-lg" />
<input
checked={areChangesHighlighted}
onChange={() => onChecked()}
type="checkbox"
className="h-5 w-5 !rounded-lg"
/>
<div className={"text-[13px] leading-[15px]"}>
Highlight All Previous Changes
</div>
Expand Down
66 changes: 40 additions & 26 deletions apps/mocksi-lite/content/EditMode/actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { saveModification } from "../../utils";
import UniversalReplace from "../../universalReplace";

export function cancelEditWithoutChanges(nodeWithTextArea: HTMLElement | null) {
if (nodeWithTextArea) {
Expand All @@ -18,35 +18,49 @@ export function applyChanges(
oldValue: string,
) {
if (nodeWithTextArea) {
const parentElement = nodeWithTextArea?.parentElement;
const previousText = getPreviousNodeValue(nodeWithTextArea, oldValue);
nodeWithTextArea?.parentElement?.replaceChild(
document.createTextNode(newValue),
nodeWithTextArea,
);
saveModification(
parentElement as HTMLElement,
parentElement?.innerHTML || parentElement?.innerText || "",
previousText || "",
);
parentElement?.normalize();
cancelEditWithoutChanges(nodeWithTextArea);
UniversalReplace.addPattern(oldValue, newValue);
}
}

function getPreviousNodeValue(
nodeWithTextArea: HTMLElement | null,
oldValue: string,
export function fragmentTextNode(
fragmentsToHighlight: Node[],
matches: RegExpMatchArray[],
textNode: Node,
newText: string,
) {
if (nodeWithTextArea) {
const ttt = nodeWithTextArea.parentElement?.cloneNode(true) as HTMLElement;
for (const node of ttt?.childNodes || []) {
// @ts-ignore
if (node?.id === "mocksiSelectedText") {
ttt?.replaceChild(document.createTextNode(oldValue), node);
ttt?.normalize();
break;
}
if (!textNode.nodeValue) {
return null;
}
const baseFragment = document.createDocumentFragment();
let cursor = 0;
let index = 0;
for (const match of matches) {
// match.index may be undefined? in which cases?????
const [startOffset, endOffset] = [
match.index || 0,
(match.index || 0) + match[0].length,
];
if (cursor < startOffset) {
baseFragment.appendChild(
document.createTextNode(
textNode.nodeValue.substring(cursor, startOffset),
),
);
}
const selectedTextFragment = document.createTextNode(newText);
fragmentsToHighlight.push(selectedTextFragment);
baseFragment.appendChild(selectedTextFragment);
cursor = endOffset;
if (index === matches.length - 1 && cursor !== textNode.nodeValue?.length) {
// end of matches
baseFragment.appendChild(
document.createTextNode(
textNode.nodeValue.substring(endOffset, textNode.nodeValue?.length),
),
);
}
return ttt.innerHTML || "";
index++;
}
return baseFragment;
}
Loading

0 comments on commit 625fdde

Please sign in to comment.