Skip to content
This repository was archived by the owner on Jun 27, 2025. It is now read-only.

Commit 2a9ab94

Browse files
isaka-jamesrwhrsbh
andauthored
Merge pull request #11 from isaka-james/dev
feat: merge enhancements for seamless code copying and documentation updates - Introduce automated scrolling for full code copying without manual zoom (Feb 26, 2025). - Consolidate README features under Feb 26 entry and add troubleshooting guidance. - Bump extension version to 1.0.5 in manifest.json. - Fix JSON syntax by replacing deprecated `optional_host_permissions` with `host_permissions`. - Incorporate fixes for partial content copying and UI improvements from collaborator. Co-authored-by: isaka-james <[email protected]> Co-authored-by: Maxym Zhyltsov <[email protected]>
2 parents 5804403 + 2a65dd4 commit 2a9ab94

File tree

4 files changed

+129
-111
lines changed

4 files changed

+129
-111
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Change Log
22

3+
### - 26 February, 2025
4+
- **Enable Full Copying:** Users can now copy code without the need to zoom out on the website. This enhancement automates the scrolling process, ensuring a seamless copying experience.
5+
36
### - 17 February, 2025
47
- **Update Link:** Recently dhiwise changed the link that refers to the project, so we changed to mirrow the changes. Which previous was `/application` but now it is `/design-converter/application`.
58

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
</p>
88

99
## 🚀 New Features & Fixes 🎉
10-
### - 17 February, 2025
10+
### - 26 February, 2025
1111

12-
- **Link Change:** Update the recently link changes to mirrow the dhiwise changes made.
12+
- **Scroll Emulation:** Automatically collect full code content via scroll emulation.
13+
- **Content Collection:** Reworked content collection mechanism. Added temporary collector for storing strings.
14+
- **Copy:** Fixed problem with partial copying of visible content only.
15+
- If the `copy code` does not appear then refresh the page, and turn on the extension.
1316

1417
[More Changes & Feature](CHANGELOG.md)
1518

backend/main.js

Lines changed: 112 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
77
}
88
});
99

10-
11-
12-
13-
1410
function enableCursor() {
1511
var targetElement = document.querySelector('.overflow-hidden.relative.h-full.false.undefined.readonlyEditor');
1612
if (targetElement) {
@@ -22,13 +18,11 @@ function enableCursor() {
2218
}
2319
}
2420

25-
2621
function addToConfuseJs() {
2722
// Step 1: Select the parent element
2823
const parentElement = document.querySelector('div.monaco-editor');
2924

3025
if (parentElement) { // Check if the parent element exists
31-
3226
// Step 2: Create a new child element
3327
const newChildElement = document.createElement('div');
3428
newChildElement.className = "monaco-editor";
@@ -43,8 +37,6 @@ function addToConfuseJs() {
4337
// Step 4: Append the new child to the parent
4438
parentElement.appendChild(newChildElement);
4539
}
46-
47-
4840
}
4941

5042
// Get the file name from a focused li
@@ -70,7 +62,6 @@ function getFileNameFromFocusedLi() {
7062
}
7163
}
7264

73-
// JavaScript
7465
function enableSelecting() {
7566
// Get all div elements with the class "monaco-editor"
7667
var divElements = document.querySelectorAll('.monaco-editor');
@@ -81,34 +72,101 @@ function enableSelecting() {
8172
if (divElement.classList.contains('no-user-select')) {
8273
// Replace "no-user-select" with "user-select"
8374
divElement.classList.replace('no-user-select', 'user-select');
84-
//alert("changed");
8575
}
8676
});
87-
8877
}
8978

9079

91-
// Define the modified getAllTextContent function
80+
function formatCode(code) {
81+
code = code.replace(/^'|'$/g, '');
82+
code = code.replace(/\\n/g, '\n');
83+
code = code.replace(/\\'/g, "'");
84+
code = code.replace(/\u00A0/g, ' ');
85+
86+
return code;
87+
}
88+
89+
// Modified getAllTextContent function
9290
function getAllTextContent(element) {
93-
let textContent = '';
94-
95-
// Iterate over child nodes of the element
96-
for (let node of element.childNodes) {
97-
// If it's an element node
98-
if (node.nodeType === Node.ELEMENT_NODE) {
99-
// If it's a "view-line" element
100-
if (node.classList.contains('view-line')) {
101-
// Append its text content to the result
102-
textContent += node.textContent.replace(/\s/g, " ") + '\n';
103-
} else {
104-
textContent += getAllTextContent(node);
91+
let contentCollector = document.createElement('div');
92+
contentCollector.style.display = 'none';
93+
document.body.appendChild(contentCollector);
94+
95+
const viewLines = element.querySelector('.view-lines');
96+
const viewport = document.querySelector('.monaco-scrollable-element');
97+
98+
if (!viewLines || !viewport) {
99+
contentCollector.remove();
100+
return Promise.resolve('/* Error! No Editor */');
101+
}
102+
103+
function captureVisibleContent() {
104+
const lines = viewLines.querySelectorAll('.view-line');
105+
let addedNew = false;
106+
107+
lines.forEach(line => {
108+
const top = parseInt(line.style.top) || 0;
109+
if (!contentCollector.querySelector(`[data-top="${top}"]`)) {
110+
const lineElement = document.createElement('div');
111+
lineElement.setAttribute('data-top', top);
112+
lineElement.setAttribute('data-content', line.textContent || '');
113+
contentCollector.appendChild(lineElement);
114+
addedNew = true;
105115
}
106-
} else if (node.nodeType === Node.TEXT_NODE) {
107-
textContent += node.textContent.replace(/\s/g, " ");
108-
}
116+
});
117+
118+
return addedNew;
109119
}
110120

111-
return textContent;
121+
function getCollectedContent() {
122+
const lines = Array.from(contentCollector.children);
123+
124+
const sortedLines = lines
125+
.map(line => ({
126+
top: parseInt(line.getAttribute('data-top')),
127+
content: line.getAttribute('data-content')
128+
}))
129+
.sort((a, b) => a.top - b.top);
130+
131+
const finalContent = sortedLines.map(line => line.content).join('\n');
132+
contentCollector.remove();
133+
return finalContent;
134+
}
135+
136+
return new Promise((resolve) => {
137+
viewport.scrollTop = 0;
138+
const maxScroll = viewport.scrollHeight;
139+
const stepSize = 10;
140+
let prevScrollPos = -1;
141+
let noNewContentCount = 0;
142+
143+
144+
setTimeout(async () => {
145+
captureVisibleContent();
146+
147+
for (let scrollPos = 0; scrollPos <= maxScroll; scrollPos += stepSize) {
148+
if (scrollPos === prevScrollPos) break;
149+
prevScrollPos = scrollPos;
150+
151+
viewport.scrollTop = scrollPos;
152+
await new Promise(r => setTimeout(r, 50));
153+
154+
const addedNew = captureVisibleContent();
155+
if (!addedNew) {
156+
noNewContentCount++;
157+
if (noNewContentCount > 3) {
158+
break;
159+
}
160+
} else {
161+
noNewContentCount = 0;
162+
}
163+
}
164+
165+
viewport.scrollTop = 0;
166+
const content = getCollectedContent();
167+
resolve(formatCode(content));
168+
}, 50);
169+
});
112170
}
113171

114172
// Function to toast a message
@@ -148,128 +206,77 @@ function showMessageDhiwise(message) {
148206
}, 3000);
149207
}
150208

151-
152-
153209
// Define the function you want to call
154210
function activate() {
155211
enableCursor(); // Here we enable cursor which is disabled on the dhiwise website
156212
addToConfuseJs(); // we need to confuse the js that is disabling us to copy the codes
157213
enableSelecting(); // Enabling the selection of codes which we can copy without problem
158214

159-
var allText = null;
160-
161-
// chrome.runtime.sendMessage({action: "fromContentScript", data: true});
162-
163-
164-
// Get the <div> element with the specified class
165215
var divElement = document.querySelector('.monaco-scrollable-element');
166-
167-
allText = getAllTextContent(divElement);
168-
//console.log(allText);
169-
170-
171-
// DELETE BEFORE STARTING
172216
var divSideBar = document.querySelector(".pro-sidebar-layout");
173-
174217
var remBtn = document.getElementById("copy-btn");
175218

176-
177219
// Check if the button exists
178-
if (document.getElementById("copy-btn")) {
220+
if (remBtn) {
179221
// Remove the button from the div
180222
divSideBar.removeChild(remBtn);
181223
}
182224

183225
// Create a new button element
184226
var button = document.createElement("button");
185-
186-
187-
// Set button text for code copy
188227
button.textContent = "Copy";
189-
190228
button.setAttribute('id', 'copy-btn');
191-
192-
// Add inline styles to the button
193229
button.style.padding = "12px 18px";
194230
button.style.backgroundColor = "blue";
195-
196-
// Append the button to the div
197231
divSideBar.appendChild(button);
198232

199-
200233
// Define the copyTextToClipboard function
201234
async function copyTextToClipboard(textToCopy) {
202235
try {
203236
if (navigator?.clipboard?.writeText) {
204-
// Attempt to write text to clipboard
205237
await navigator.clipboard.writeText(textToCopy);
206-
207238
}
208239
} catch (err) {
209240
console.error(err);
210241
}
211242
}
212243

213244
// Add an event listener to the button
214-
button.addEventListener("click", function () {
215-
216-
217-
if (document.getElementsByClassName('editorImage')[0]) {
218-
const imageDiv = document.querySelector('.editorImage img');
219-
const canvas = document.createElement('canvas');
220-
const ctx = canvas.getContext('2d');
221-
222-
// Set canvas dimensions to match image
223-
canvas.width = imageDiv.naturalWidth;
224-
canvas.height = imageDiv.naturalHeight;
225-
226-
// Draw the image on the canvas
227-
ctx.drawImage(imageDiv, 0, 0);
228-
229-
// Convert the canvas to a data URL
230-
const dataURL = canvas.toDataURL('image/png');
231-
232-
// Create a link element and trigger a download
233-
const link = document.createElement('a');
234-
link.href = dataURL;
235-
link.download = getFileNameFromFocusedLi(); // Filename for the downloaded image
236-
link.click();
237-
showMessageDhiwise("Picture was downloaded Successfully!");
238-
} else {
239-
// Call the copyTextToClipboard function with the text to copy
240-
copyTextToClipboard(allText);
245+
button.addEventListener("click", async function () {
246+
if (document.getElementsByClassName('editorImage')[0]) {
247+
const imageDiv = document.querySelector('.editorImage img');
248+
const canvas = document.createElement('canvas');
249+
const ctx = canvas.getContext('2d');
250+
canvas.width = imageDiv.naturalWidth;
251+
canvas.height = imageDiv.naturalHeight;
252+
ctx.drawImage(imageDiv, 0, 0);
253+
const dataURL = canvas.toDataURL('image/png');
254+
const link = document.createElement('a');
255+
link.href = dataURL;
256+
link.download = getFileNameFromFocusedLi();
257+
link.click();
258+
showMessageDhiwise("Picture was downloaded Successfully!");
259+
} else {
260+
const currentDivElement = document.querySelector('.monaco-scrollable-element');
261+
if (currentDivElement) {
262+
const formattedText = await getAllTextContent(currentDivElement);
263+
await copyTextToClipboard(formattedText);
241264
showMessageDhiwise("Code was Copied Successfully!");
265+
} else {
266+
showMessageDhiwise("No content found to copy!");
242267
}
243-
244-
245-
activate();
246-
});
247-
248-
249-
268+
}
269+
activate();
270+
});
250271
}
251272

252-
253273
document.addEventListener("DOMContentLoaded", function () {
254-
255-
256-
// Get reference to the <section> element
257274
var sectionElement = document.querySelector('section');
258-
259-
260-
// Add click event listener to the <section> element
261275
sectionElement.addEventListener('click', () => {
262-
// This will ensure that whenever a click occurs on the <section> element,
263-
// the class of the <div> element is always 'user-select'
264276
if (sectionElement.classList.contains('no-user-select')) {
265277
sectionElement.classList.remove('no-user-select');
266278
}
267279
sectionElement.classList.add('user-select');
268-
269280
});
270-
271-
272-
// Ensure that the body element is always selectable
273281
document.div.style.userSelect = 'text';
274-
275-
});
282+
});

manifest.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
{
22
"name": "Dhiwise Code Copy",
3-
"version": "1.0.1",
3+
"version": "1.0.5",
44
"description": "Copy your codes from your converted dhiwise application made easy!",
55
"manifest_version": 3,
66
"author": "Isaka-James",
7+
"icons": {
8+
"16": "dhiwise.png",
9+
"32": "dhiwise.png",
10+
"48": "dhiwise.png",
11+
"64": "dhiwise.png"
12+
},
713
"action": {
814
"default_icon": "dhiwise.png",
915
"default_popup": "front-end/index.html",
@@ -16,9 +22,8 @@
1622
"permissions": [
1723
"activeTab", "tabs"
1824
],
19-
"optional_host_permissions":[
20-
"https://*/*",
21-
"http://*/*"
25+
"host_permissions":[
26+
"https://app.dhiwise.com/*"
2227
]
2328

2429
}

0 commit comments

Comments
 (0)