From 85e87ec717e6c6482ba3eb862d5a69ac1496ce88 Mon Sep 17 00:00:00 2001
From: varun-s22 <93476421+varun-s22@users.noreply.github.com>
Date: Wed, 28 Dec 2022 16:45:25 +0530
Subject: [PATCH 1/3] Fixed ReadMe uploads
Now the readMe can be easily pushed to github with the new leetcode
Here are features which are currently extracted
* Problem Title
* Problem Link
* Problem Statement
* Problem Description
* Language used by the user
* Submission stats
---
manifest.json | 8 +-
scripts/newleetcode.js | 784 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 790 insertions(+), 2 deletions(-)
create mode 100644 scripts/newleetcode.js
diff --git a/manifest.json b/manifest.json
index 795f250b..a283a2dc 100644
--- a/manifest.json
+++ b/manifest.json
@@ -23,6 +23,8 @@
"https://api.github.com/*",
"https://leetcode.com/*",
"https://practice.geeksforgeeks.org/*",
+ "https://*.leetcode.com/*",
+ "https://*.leetcode.cn/*",
"tabs",
"unlimitedStorage",
"storage"
@@ -32,10 +34,12 @@
"matches": [
"https://leetcode.com/*",
"https://github.com/*",
- "https://practice.geeksforgeeks.org/*"
+ "https://practice.geeksforgeeks.org/*",
+ "https://*.leetcode.com/*",
+ "https://*.leetcode.cn/*"
],
"js": [
- "scripts/leetcode.js",
+ "scripts/newleetcode.js",
"scripts/authorize.js",
"scripts/gfg.js"
],
diff --git a/scripts/newleetcode.js b/scripts/newleetcode.js
new file mode 100644
index 00000000..7d6c2dab
--- /dev/null
+++ b/scripts/newleetcode.js
@@ -0,0 +1,784 @@
+/* Enum for languages supported by LeetCode. */
+const languages = {
+ Python: '.py',
+ Python3: '.py',
+ 'C++': '.cpp',
+ C: '.c',
+ Java: '.java',
+ 'C#': '.cs',
+ JavaScript: '.js',
+ Javascript: '.js',
+ Ruby: '.rb',
+ Swift: '.swift',
+ Go: '.go',
+ Kotlin: '.kt',
+ Scala: '.scala',
+ Rust: '.rs',
+ PHP: '.php',
+ TypeScript: '.ts',
+ MySQL: '.sql',
+ 'MS SQL Server': '.sql',
+ Oracle: '.sql',
+};
+
+/* Commit messages */
+const readmeMsg = 'Create README - LeetHub';
+const discussionMsg = 'Prepend discussion post - LeetHub';
+const createNotesMsg = 'Attach NOTES - LeetHub';
+const pattern = /https?:\/\/.*leetcode.com\/problems\/.*\/submissions\/\d*/;
+
+// problem types
+const NORMAL_PROBLEM = 0;
+const EXPLORE_SECTION_PROBLEM = 1;
+
+/* Difficulty of most recenty submitted question */
+let difficulty = '';
+
+/* state of upload for progress */
+let uploadState = { uploading: false };
+
+/* Util function to check if an element exists */
+function checkElem(elem) {
+ return elem && elem.length > 0;
+}
+
+/* Get file extension for submission */
+function findLanguage() {
+ const tag = [
+ ...document.getElementsByClassName(
+ 'ant-select-selection-selected-value',
+ ),
+ ...document.getElementsByClassName('Select-value-label'),
+ ];
+ if (tag && tag.length > 0) {
+ for (let i = 0; i < tag.length; i += 1) {
+ const elem = tag[i].textContent;
+ if (elem !== undefined && languages[elem] !== undefined) {
+ return languages[elem]; // should generate respective file extension
+ }
+ }
+ }
+ return null;
+}
+
+/* Main function for uploading code to GitHub repo, and callback cb is called if success */
+const upload = (
+ token,
+ hook,
+ code,
+ directory,
+ filename,
+ sha,
+ msg,
+ cb = undefined,
+) => {
+ // To validate user, load user object from GitHub.
+ const URL = `https://api.github.com/repos/${hook}/contents/${directory}/${filename}`;
+
+ /* Define Payload */
+ let data = {
+ message: msg,
+ content: code,
+ sha,
+ };
+
+ data = JSON.stringify(data);
+
+ const xhr = new XMLHttpRequest();
+ xhr.addEventListener('readystatechange', function () {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200 || xhr.status === 201) {
+ const updatedSha = JSON.parse(xhr.responseText).content.sha; // get updated SHA.
+
+ chrome.storage.local.get('stats', (data2) => {
+ let { stats } = data2;
+ if (stats === null || stats === {} || stats === undefined) {
+ // create stats object
+ stats = {};
+ stats.solved = 0;
+ stats.easy = 0;
+ stats.medium = 0;
+ stats.hard = 0;
+ stats.sha = {};
+ }
+ const filePath = directory + filename;
+ // Only increment solved problems statistics once
+ // New submission commits twice (README and problem)
+ if (filename === 'README.md' && sha === null) {
+ stats.solved += 1;
+ stats.easy += difficulty === 'Easy' ? 1 : 0;
+ stats.medium += difficulty === 'Medium' ? 1 : 0;
+ stats.hard += difficulty === 'Hard' ? 1 : 0;
+ }
+ stats.sha[filePath] = updatedSha; // update sha key.
+ chrome.storage.local.set({ stats }, () => {
+ console.log(
+ `Successfully committed ${filename} to github`,
+ );
+
+ // if callback is defined, call it
+ if (cb !== undefined) {
+ cb();
+ }
+ });
+ });
+ }
+ }
+ });
+ xhr.open('PUT', URL, true);
+ xhr.setRequestHeader('Authorization', `token ${token}`);
+ xhr.setRequestHeader('Accept', 'application/vnd.github.v3+json');
+ xhr.send(data);
+};
+
+/* Main function for updating code on GitHub Repo */
+/* Currently only used for prepending discussion posts to README */
+/* callback cb is called on success if it is defined */
+const update = (
+ token,
+ hook,
+ addition,
+ directory,
+ msg,
+ prepend,
+ cb = undefined,
+) => {
+ const URL = `https://api.github.com/repos/${hook}/contents/${directory}/README.md`;
+
+ /* Read from existing file on GitHub */
+ const xhr = new XMLHttpRequest();
+ xhr.addEventListener('readystatechange', function () {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200 || xhr.status === 201) {
+ const response = JSON.parse(xhr.responseText);
+ const existingContent = decodeURIComponent(
+ escape(atob(response.content)),
+ );
+ let newContent = '';
+
+ /* Discussion posts prepended at top of README */
+ /* Future implementations may require appending to bottom of file */
+ if (prepend) {
+ newContent = btoa(
+ unescape(encodeURIComponent(addition + existingContent)),
+ );
+ }
+
+ /* Write file with new content to GitHub */
+ upload(
+ token,
+ hook,
+ newContent,
+ directory,
+ 'README.md',
+ response.sha,
+ msg,
+ cb,
+ );
+ }
+ }
+ });
+ xhr.open('GET', URL, true);
+ xhr.setRequestHeader('Authorization', `token ${token}`);
+ xhr.setRequestHeader('Accept', 'application/vnd.github.v3+json');
+ xhr.send();
+};
+
+function uploadGit(
+ code,
+ problemName,
+ fileName,
+ msg,
+ action,
+ prepend = true,
+ cb = undefined,
+ _diff = undefined,
+) {
+ // Assign difficulty
+ if (_diff && _diff !== undefined) {
+ difficulty = _diff.trim();
+ }
+
+ /* Get necessary payload data */
+ chrome.storage.local.get('leethub_token', (t) => {
+ const token = t.leethub_token;
+ if (token) {
+ chrome.storage.local.get('mode_type', (m) => {
+ const mode = m.mode_type;
+ if (mode === 'commit') {
+ /* Get hook */
+ chrome.storage.local.get('leethub_hook', (h) => {
+ const hook = h.leethub_hook;
+ if (hook) {
+ /* Get SHA, if it exists */
+
+ /* to get unique key */
+ const filePath = problemName + fileName;
+ chrome.storage.local.get('stats', (s) => {
+ const { stats } = s;
+ let sha = null;
+
+ if (
+ stats !== undefined &&
+ stats.sha !== undefined &&
+ stats.sha[filePath] !== undefined
+ ) {
+ sha = stats.sha[filePath];
+ }
+
+ if (action === 'upload') {
+ /* Upload to git. */
+ upload(
+ token,
+ hook,
+ code,
+ problemName,
+ fileName,
+ sha,
+ msg,
+ cb,
+ );
+ } else if (action === 'update') {
+ /* Update on git */
+ update(
+ token,
+ hook,
+ code,
+ problemName,
+ msg,
+ prepend,
+ cb,
+ );
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+ });
+}
+
+/* Function for finding and parsing the full code. */
+/* - At first find the submission details url. */
+/* - Then send a request for the details page. */
+/* - Finally, parse the code from the html reponse. */
+/* - Also call the callback if available when upload is success */
+function findCode(
+ uploadGit,
+ problemName,
+ fileName,
+ msg,
+ action,
+ cb = undefined,
+) {
+ /* Get the submission details url from the submission page. */
+ var submissionURL;
+ const e = document.getElementsByClassName('status-column__3SUg');
+ if (checkElem(e)) {
+ // for normal problem submisson
+ const submissionRef = e[1].innerHTML.split(' ')[1];
+ submissionURL =
+ 'https://leetcode.com' +
+ submissionRef.split('=')[1].slice(1, -1);
+ } else {
+ // for a submission in explore section
+ const submissionRef = document.getElementById('result-state');
+ submissionURL = submissionRef.href;
+ }
+ if (submissionURL != undefined) {
+ /* Request for the submission details page */
+ const xhttp = new XMLHttpRequest();
+ xhttp.onreadystatechange = function () {
+ if (this.readyState == 4 && this.status == 200) {
+ /* received submission details as html reponse. */
+ var doc = new DOMParser().parseFromString(
+ this.responseText,
+ 'text/html',
+ );
+ /* the response has a js object called pageData. */
+ /* Pagedata has the details data with code about that submission */
+ var scripts = doc.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ var text = scripts[i].innerText;
+ if (text.includes('pageData')) {
+ /* Considering the pageData as text and extract the substring
+ which has the full code */
+ var firstIndex = text.indexOf('submissionCode');
+ var lastIndex = text.indexOf('editCodeUrl');
+ var slicedText = text.slice(firstIndex, lastIndex);
+ /* slicedText has code as like as. (submissionCode: 'Details code'). */
+ /* So finding the index of first and last single inverted coma. */
+ var firstInverted = slicedText.indexOf("'");
+ var lastInverted = slicedText.lastIndexOf("'");
+ /* Extract only the code */
+ var codeUnicoded = slicedText.slice(
+ firstInverted + 1,
+ lastInverted,
+ );
+ /* The code has some unicode. Replacing all unicode with actual characters */
+ var code = codeUnicoded.replace(
+ /\\u[\dA-F]{4}/gi,
+ function (match) {
+ return String.fromCharCode(
+ parseInt(match.replace(/\\u/g, ''), 16),
+ );
+ },
+ );
+
+ /*
+ for a submisssion in explore section we do not get probStat beforehand
+ so, parse statistics from submisson page
+ */
+ if (!msg) {
+ slicedText = text.slice(
+ text.indexOf('runtime'),
+ text.indexOf('memory'),
+ );
+ const resultRuntime = slicedText.slice(
+ slicedText.indexOf("'") + 1,
+ slicedText.lastIndexOf("'"),
+ );
+ slicedText = text.slice(
+ text.indexOf('memory'),
+ text.indexOf('total_correct'),
+ );
+ const resultMemory = slicedText.slice(
+ slicedText.indexOf("'") + 1,
+ slicedText.lastIndexOf("'"),
+ );
+ msg = `Time: ${resultRuntime}, Memory: ${resultMemory} - LeetHub`;
+ }
+
+ if (code != null) {
+ setTimeout(function () {
+ uploadGit(
+ btoa(unescape(encodeURIComponent(code))),
+ problemName,
+ fileName,
+ msg,
+ action,
+ true,
+ cb,
+ );
+ }, 2000);
+ }
+ }
+ }
+ }
+ };
+
+ xhttp.open('GET', submissionURL, true);
+ xhttp.send();
+ }
+}
+
+/* Main parser function for the code */
+function parseCode() {
+ const e = document.getElementsByClassName('CodeMirror-code');
+ if (e !== undefined && e.length > 0) {
+ const elem = e[0];
+ let parsedCode = '';
+ const textArr = elem.innerText.split('\n');
+ for (let i = 1; i < textArr.length; i += 2) {
+ parsedCode += `${textArr[i]}\n`;
+ }
+ return parsedCode;
+ }
+ return null;
+}
+
+function convertToSlug(string) {
+ const a =
+ 'àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;';
+ const b =
+ 'aaaaaaaaaacccddeeeeeeeegghiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz------';
+ const p = new RegExp(a.split('').join('|'), 'g');
+
+ return string
+ .toString()
+ .toLowerCase()
+ .replace(/\s+/g, '-') // Replace spaces with -
+ .replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters
+ .replace(/&/g, '-and-') // Replace & with 'and'
+ .replace(/[^\w\-]+/g, '') // Remove all non-word characters
+ .replace(/\-\-+/g, '-') // Replace multiple - with single -
+ .replace(/^-+/, '') // Trim - from start of text
+ .replace(/-+$/, ''); // Trim - from end of text
+}
+function getProblemNameSlug(questionTitle) {
+ return addLeadingZeros(convertToSlug(questionTitle));
+}
+
+function addLeadingZeros(title) {
+ const maxTitlePrefixLength = 4;
+ var len = title.split('-')[0].length;
+ if (len < maxTitlePrefixLength) {
+ return '0'.repeat(4 - len) + title;
+ }
+ return title;
+}
+
+/* Parser function for the question and tags */
+function parseQuestion() {
+ var questionUrl = window.location.href;
+ questionUrl = questionUrl.split('submissions')[0];
+
+ let question = document.querySelector('meta[name="description"]');
+ if (question) {
+ question = question.content;
+ }
+
+ let qArray = question.split(' - ');
+ question = qArray[1];
+ const qbody = question;
+
+ // Problem title.
+ let qtitle = qArray[0].trim();
+
+ // Final formatting of the contents of the README for each problem
+ const markdown = `
${qbody}`;
+ return { markdown, title: qtitle };
+}
+
+/* Parser function for time/space stats */
+function parseStats() {
+ let probStats = document.getElementsByClassName('data__HC-i');
+ if (!checkElem(probStats)) {
+ probStats = document.getElementsByClassName(
+ 'text-label-1 dark:text-dark-label-1 ml-2 font-medium',
+ );
+ if (!checkElem(probStats)) {
+ return null;
+ }
+ }
+ const percentageStats = document.getElementsByClassName(
+ 'text-white dark:text-dark-white ml-2 rounded-xl px-1.5 font-medium',
+ );
+ let time = probStats[0].textContent;
+ let timePercentile;
+ let space;
+ let spacePercentile;
+ if (!checkElem(percentageStats)) {
+ timePercentile = probStats[1].textContent;
+ space = probStats[2].textContent;
+ spacePercentile = probStats[3].textContent;
+ } else {
+ timePercentile = percentageStats[0].textContent;
+ space = probStats[1].textContent;
+ spacePercentile = percentageStats[1].textContent;
+ }
+ // Format commit message
+ return `Time: ${time} (${timePercentile}), Space: ${space} (${spacePercentile}) - LeetHub`;
+}
+
+document.addEventListener('click', (event) => {
+ const element = event.target;
+ const oldPath = window.location.pathname;
+
+ /* Act on Post button click */
+ /* Complex since "New" button shares many of the same properties as "Post button */
+ if (
+ element.classList.contains('icon__3Su4') ||
+ element.parentElement.classList.contains('icon__3Su4') ||
+ element.parentElement.classList.contains(
+ 'btn-content-container__214G',
+ ) ||
+ element.parentElement.classList.contains('header-right__2UzF')
+ ) {
+ setTimeout(function () {
+ /* Only post if post button was clicked and url changed */
+ if (
+ oldPath !== window.location.pathname &&
+ oldPath ===
+ window.location.pathname.substring(0, oldPath.length) &&
+ !Number.isNaN(window.location.pathname.charAt(oldPath.length))
+ ) {
+ const date = new Date();
+ const currentDate = `${date.getDate()}/${date.getMonth()}/${date.getFullYear()} at ${date.getHours()}:${date.getMinutes()}`;
+ const addition = `[Discussion Post (created on ${currentDate})](${window.location}) \n`;
+ const problemName = window.location.pathname.split('/')[2]; // must be true.
+
+ uploadGit(
+ addition,
+ problemName,
+ 'README.md',
+ discussionMsg,
+ 'update',
+ );
+ }
+ }, 1000);
+ }
+});
+
+/* function to get the notes if there is any
+ the note should be opened atleast once for this to work
+ this is because the dom is populated after data is fetched by opening the note */
+function getNotesIfAny() {
+ // there are no notes on expore
+ if (document.URL.startsWith('https://leetcode.com/explore/'))
+ return '';
+
+ notes = '';
+ if (
+ checkElem(document.getElementsByClassName('notewrap__eHkN')) &&
+ checkElem(
+ document
+ .getElementsByClassName('notewrap__eHkN')[0]
+ .getElementsByClassName('CodeMirror-code'),
+ )
+ ) {
+ notesdiv = document
+ .getElementsByClassName('notewrap__eHkN')[0]
+ .getElementsByClassName('CodeMirror-code')[0];
+ if (notesdiv) {
+ for (i = 0; i < notesdiv.childNodes.length; i++) {
+ if (notesdiv.childNodes[i].childNodes.length == 0) continue;
+ text = notesdiv.childNodes[i].childNodes[0].innerText;
+ if (text) {
+ notes = `${notes}\n${text.trim()}`.trim();
+ }
+ }
+ }
+ }
+ return notes.trim();
+}
+
+const loader = setInterval(() => {
+ let code = null;
+ let probStatement = null;
+ let probStats = null;
+ let probType;
+ let languageDiv = document.querySelector('.leading-4')
+ ? document.querySelector('.leading-4')
+ : null;
+
+ const language = languageDiv
+ ? languages[languageDiv.innerText]
+ : findLanguage();
+
+ let currentLink = document.location.href;
+ let solution = currentLink.match(pattern);
+
+ const successTag = document.getElementsByClassName('success__3Ai7');
+ const resultState = document.getElementById('result-state');
+ var success = solution ? true : false;
+ // check success tag for a normal problem
+ if (
+ checkElem(successTag) &&
+ successTag[0].className === 'success__3Ai7' &&
+ successTag[0].innerText.trim() === 'Success'
+ ) {
+ console.log(successTag[0]);
+ success = true;
+ probType = NORMAL_PROBLEM;
+ }
+
+ // check success state for a explore section problem
+ else if (
+ resultState &&
+ resultState.className === 'text-success' &&
+ resultState.innerText === 'Accepted'
+ ) {
+ success = true;
+ probType = EXPLORE_SECTION_PROBLEM;
+ }
+ if (success) {
+ probStatement = parseQuestion().markdown;
+ probStats = parseStats();
+ }
+
+ if (probStatement !== null) {
+ const problemName = getProblemNameSlug(parseQuestion().title);
+ if (language !== null) {
+ // start upload indicator here
+ startUpload();
+ chrome.storage.local.get('stats', (s) => {
+ const { stats } = s;
+ const filePath = problemName + problemName + language;
+ let sha = null;
+ if (
+ stats !== undefined &&
+ stats.sha !== undefined &&
+ stats.sha[filePath] !== undefined
+ ) {
+ sha = stats.sha[filePath];
+ }
+
+ /* Only create README if not already created */
+ if (sha === null) {
+ /* @TODO: Change this setTimeout to Promise */
+ uploadGit(
+ btoa(unescape(encodeURIComponent(probStatement))),
+ problemName,
+ 'README.md',
+ readmeMsg,
+ 'upload',
+ );
+ }
+ });
+
+ /* get the notes and upload it */
+ /* only upload notes if there is any */
+ notes = getNotesIfAny();
+ if (notes.length > 0) {
+ setTimeout(function () {
+ if (notes != undefined && notes.length != 0) {
+ console.log('Create Notes');
+ // means we can upload the notes too
+ uploadGit(
+ btoa(unescape(encodeURIComponent(notes))),
+ problemName,
+ 'NOTES.md',
+ createNotesMsg,
+ 'upload',
+ );
+ }
+ }, 500);
+ }
+
+ /* Upload code to Git */
+ setTimeout(function () {
+ findCode(
+ uploadGit,
+ problemName,
+ problemName + language,
+ probStats,
+ 'upload',
+ // callback is called when the code upload to git is a success
+ () => {
+ if (uploadState['countdown'])
+ clearTimeout(uploadState['countdown']);
+ delete uploadState['countdown'];
+ uploadState.uploading = false;
+ markUploaded();
+ },
+ ); // Encode `code` to base64
+ }, 1000);
+ }
+ }
+}, 1000);
+
+/* Since we dont yet have callbacks/promises that helps to find out if things went bad */
+/* we will start 10 seconds counter and even after that upload is not complete, then we conclude its failed */
+function startUploadCountDown() {
+ uploadState.uploading = true;
+ uploadState['countdown'] = setTimeout(() => {
+ if ((uploadState.uploading = true)) {
+ // still uploading, then it failed
+ uploadState.uploading = false;
+ markUploadFailed();
+ }
+ }, 10000);
+}
+
+/* we will need specific anchor element that is specific to the page you are in Eg. Explore */
+function insertToAnchorElement(elem) {
+ if (document.URL.startsWith('https://leetcode.com/explore/')) {
+ // means we are in explore page
+ action = document.getElementsByClassName('action');
+ if (
+ checkElem(action) &&
+ checkElem(action[0].getElementsByClassName('row')) &&
+ checkElem(
+ action[0]
+ .getElementsByClassName('row')[0]
+ .getElementsByClassName('col-sm-6'),
+ ) &&
+ action[0]
+ .getElementsByClassName('row')[0]
+ .getElementsByClassName('col-sm-6').length > 1
+ ) {
+ target = action[0]
+ .getElementsByClassName('row')[0]
+ .getElementsByClassName('col-sm-6')[1];
+ elem.className = 'pull-left';
+ if (target.childNodes.length > 0)
+ target.childNodes[0].prepend(elem);
+ }
+ } else {
+ if (checkElem(document.getElementsByClassName('action__38Xc'))) {
+ target = document.getElementsByClassName('action__38Xc')[0];
+ elem.className = 'runcode-wrapper__8rXm';
+ if (target.childNodes.length > 0)
+ target.childNodes[0].prepend(elem);
+ }
+ }
+}
+
+/* start upload will inject a spinner on left side to the "Run Code" button */
+function startUpload() {
+ try {
+ elem = document.getElementById('leethub_progress_anchor_element');
+ if (!elem) {
+ elem = document.createElement('span');
+ elem.id = 'leethub_progress_anchor_element';
+ elem.style = 'margin-right: 20px;padding-top: 2px;';
+ }
+ elem.innerHTML = ``;
+ target = insertToAnchorElement(elem);
+ // start the countdown
+ startUploadCountDown();
+ } catch (error) {
+ // generic exception handler for time being so that existing feature doesnt break but
+ // error gets logged
+ console.log(error);
+ }
+}
+
+/* This will create a tick mark before "Run Code" button signalling LeetHub has done its job */
+function markUploaded() {
+ elem = document.getElementById('leethub_progress_elem');
+ if (elem) {
+ elem.className = '';
+ style =
+ 'display: inline-block;transform: rotate(45deg);height:24px;width:12px;border-bottom:7px solid #78b13f;border-right:7px solid #78b13f;';
+ elem.style = style;
+ }
+}
+
+/* This will create a failed tick mark before "Run Code" button signalling that upload failed */
+function markUploadFailed() {
+ elem = document.getElementById('leethub_progress_elem');
+ if (elem) {
+ elem.className = '';
+ style =
+ 'display: inline-block;transform: rotate(45deg);height:24px;width:12px;border-bottom:7px solid red;border-right:7px solid red;';
+ elem.style = style;
+ }
+}
+
+/* Sync to local storage */
+chrome.storage.local.get('isSync', (data) => {
+ keys = [
+ 'leethub_token',
+ 'leethub_username',
+ 'pipe_leethub',
+ 'stats',
+ 'leethub_hook',
+ 'mode_type',
+ ];
+ if (!data || !data.isSync) {
+ keys.forEach((key) => {
+ chrome.storage.sync.get(key, (data) => {
+ chrome.storage.local.set({ [key]: data[key] });
+ });
+ });
+ chrome.storage.local.set({ isSync: true }, (data) => {
+ console.log('LeetHub Synced to local values');
+ });
+ } else {
+ console.log('LeetHub Local storage already synced!');
+ }
+});
+
+// inject the style
+injectStyle();
+
+/* inject css style required for the upload progress feature */
+function injectStyle() {
+ const style = document.createElement('style');
+ style.textContent =
+ '.leethub_progress {pointer-events: none;width: 2.0em;height: 2.0em;border: 0.4em solid transparent;border-color: #eee;border-top-color: #3E67EC;border-radius: 50%;animation: loadingspin 1s linear infinite;} @keyframes loadingspin { 100% { transform: rotate(360deg) }}';
+ document.head.append(style);
+}
From 9de65e59d6019ec3c86e7bc9f91093a30280809f Mon Sep 17 00:00:00 2001
From: varun-s22 <93476421+varun-s22@users.noreply.github.com>
Date: Thu, 29 Dec 2022 02:27:24 +0530
Subject: [PATCH 2/3] Fixed Code Uploads
Now the code can be easily pushed as well
The Code and the ReadMe(question statement) can be pushed to github,
All the features are extracted. Notes/Discussions are not extracted
---
scripts/newleetcode.js | 286 +++++++++--------------------------------
1 file changed, 61 insertions(+), 225 deletions(-)
diff --git a/scripts/newleetcode.js b/scripts/newleetcode.js
index 7d6c2dab..8d8b180c 100644
--- a/scripts/newleetcode.js
+++ b/scripts/newleetcode.js
@@ -36,6 +36,7 @@ let difficulty = '';
/* state of upload for progress */
let uploadState = { uploading: false };
+let elem;
/* Util function to check if an element exists */
function checkElem(elem) {
@@ -272,120 +273,39 @@ function findCode(
action,
cb = undefined,
) {
- /* Get the submission details url from the submission page. */
- var submissionURL;
- const e = document.getElementsByClassName('status-column__3SUg');
- if (checkElem(e)) {
- // for normal problem submisson
- const submissionRef = e[1].innerHTML.split(' ')[1];
- submissionURL =
- 'https://leetcode.com' +
- submissionRef.split('=')[1].slice(1, -1);
- } else {
- // for a submission in explore section
- const submissionRef = document.getElementById('result-state');
- submissionURL = submissionRef.href;
+ let codeUnicoded = null;
+ /* Extract only the code */
+
+ let codeDiv = document.querySelector('code');
+ if (!codeDiv) {
+ return null;
}
- if (submissionURL != undefined) {
- /* Request for the submission details page */
- const xhttp = new XMLHttpRequest();
- xhttp.onreadystatechange = function () {
- if (this.readyState == 4 && this.status == 200) {
- /* received submission details as html reponse. */
- var doc = new DOMParser().parseFromString(
- this.responseText,
- 'text/html',
+ codeUnicoded = codeDiv.innerText;
+
+ if (codeUnicoded !== null) {
+ /* The code has some unicode. Replacing all unicode with actual characters */
+ var code = codeUnicoded.replace(
+ /\\u[\dA-F]{4}/gi,
+ function (match) {
+ return String.fromCharCode(
+ parseInt(match.replace(/\\u/g, ''), 16),
);
- /* the response has a js object called pageData. */
- /* Pagedata has the details data with code about that submission */
- var scripts = doc.getElementsByTagName('script');
- for (var i = 0; i < scripts.length; i++) {
- var text = scripts[i].innerText;
- if (text.includes('pageData')) {
- /* Considering the pageData as text and extract the substring
- which has the full code */
- var firstIndex = text.indexOf('submissionCode');
- var lastIndex = text.indexOf('editCodeUrl');
- var slicedText = text.slice(firstIndex, lastIndex);
- /* slicedText has code as like as. (submissionCode: 'Details code'). */
- /* So finding the index of first and last single inverted coma. */
- var firstInverted = slicedText.indexOf("'");
- var lastInverted = slicedText.lastIndexOf("'");
- /* Extract only the code */
- var codeUnicoded = slicedText.slice(
- firstInverted + 1,
- lastInverted,
- );
- /* The code has some unicode. Replacing all unicode with actual characters */
- var code = codeUnicoded.replace(
- /\\u[\dA-F]{4}/gi,
- function (match) {
- return String.fromCharCode(
- parseInt(match.replace(/\\u/g, ''), 16),
- );
- },
- );
-
- /*
- for a submisssion in explore section we do not get probStat beforehand
- so, parse statistics from submisson page
- */
- if (!msg) {
- slicedText = text.slice(
- text.indexOf('runtime'),
- text.indexOf('memory'),
- );
- const resultRuntime = slicedText.slice(
- slicedText.indexOf("'") + 1,
- slicedText.lastIndexOf("'"),
- );
- slicedText = text.slice(
- text.indexOf('memory'),
- text.indexOf('total_correct'),
- );
- const resultMemory = slicedText.slice(
- slicedText.indexOf("'") + 1,
- slicedText.lastIndexOf("'"),
- );
- msg = `Time: ${resultRuntime}, Memory: ${resultMemory} - LeetHub`;
- }
-
- if (code != null) {
- setTimeout(function () {
- uploadGit(
- btoa(unescape(encodeURIComponent(code))),
- problemName,
- fileName,
- msg,
- action,
- true,
- cb,
- );
- }, 2000);
- }
- }
- }
- }
- };
-
- xhttp.open('GET', submissionURL, true);
- xhttp.send();
+ },
+ );
}
-}
-
-/* Main parser function for the code */
-function parseCode() {
- const e = document.getElementsByClassName('CodeMirror-code');
- if (e !== undefined && e.length > 0) {
- const elem = e[0];
- let parsedCode = '';
- const textArr = elem.innerText.split('\n');
- for (let i = 1; i < textArr.length; i += 2) {
- parsedCode += `${textArr[i]}\n`;
- }
- return parsedCode;
+ if (codeUnicoded !== null && code !== null) {
+ setTimeout(function () {
+ uploadGit(
+ btoa(unescape(encodeURIComponent(code))),
+ problemName,
+ fileName,
+ msg,
+ action,
+ true,
+ cb,
+ );
+ }, 2000);
}
- return null;
}
function convertToSlug(string) {
@@ -407,16 +327,7 @@ function convertToSlug(string) {
.replace(/-+$/, ''); // Trim - from end of text
}
function getProblemNameSlug(questionTitle) {
- return addLeadingZeros(convertToSlug(questionTitle));
-}
-
-function addLeadingZeros(title) {
- const maxTitlePrefixLength = 4;
- var len = title.split('-')[0].length;
- if (len < maxTitlePrefixLength) {
- return '0'.repeat(4 - len) + title;
- }
- return title;
+ return convertToSlug(questionTitle);
}
/* Parser function for the question and tags */
@@ -428,46 +339,35 @@ function parseQuestion() {
if (question) {
question = question.content;
}
-
let qArray = question.split(' - ');
- question = qArray[1];
- const qbody = question;
+ question = qArray.slice(1).join(' ');
// Problem title.
let qtitle = qArray[0].trim();
// Final formatting of the contents of the README for each problem
- const markdown = `
${qbody}`;
+ const markdown = `
${question}`;
return { markdown, title: qtitle };
}
/* Parser function for time/space stats */
function parseStats() {
- let probStats = document.getElementsByClassName('data__HC-i');
+ let probStats = document.getElementsByClassName(
+ 'text-label-1 dark:text-dark-label-1 ml-2 font-medium',
+ );
if (!checkElem(probStats)) {
- probStats = document.getElementsByClassName(
- 'text-label-1 dark:text-dark-label-1 ml-2 font-medium',
- );
- if (!checkElem(probStats)) {
- return null;
- }
+ return null;
}
const percentageStats = document.getElementsByClassName(
'text-white dark:text-dark-white ml-2 rounded-xl px-1.5 font-medium',
);
let time = probStats[0].textContent;
- let timePercentile;
- let space;
- let spacePercentile;
+ let space = probStats[1].textContent;
if (!checkElem(percentageStats)) {
- timePercentile = probStats[1].textContent;
- space = probStats[2].textContent;
- spacePercentile = probStats[3].textContent;
- } else {
- timePercentile = percentageStats[0].textContent;
- space = probStats[1].textContent;
- spacePercentile = percentageStats[1].textContent;
+ return null;
}
+ let timePercentile = percentageStats[0].textContent;
+ let spacePercentile = percentageStats[1].textContent;
// Format commit message
return `Time: ${time} (${timePercentile}), Space: ${space} (${spacePercentile}) - LeetHub`;
}
@@ -511,44 +411,10 @@ document.addEventListener('click', (event) => {
}
});
-/* function to get the notes if there is any
- the note should be opened atleast once for this to work
- this is because the dom is populated after data is fetched by opening the note */
-function getNotesIfAny() {
- // there are no notes on expore
- if (document.URL.startsWith('https://leetcode.com/explore/'))
- return '';
-
- notes = '';
- if (
- checkElem(document.getElementsByClassName('notewrap__eHkN')) &&
- checkElem(
- document
- .getElementsByClassName('notewrap__eHkN')[0]
- .getElementsByClassName('CodeMirror-code'),
- )
- ) {
- notesdiv = document
- .getElementsByClassName('notewrap__eHkN')[0]
- .getElementsByClassName('CodeMirror-code')[0];
- if (notesdiv) {
- for (i = 0; i < notesdiv.childNodes.length; i++) {
- if (notesdiv.childNodes[i].childNodes.length == 0) continue;
- text = notesdiv.childNodes[i].childNodes[0].innerText;
- if (text) {
- notes = `${notes}\n${text.trim()}`.trim();
- }
- }
- }
- }
- return notes.trim();
-}
-
const loader = setInterval(() => {
- let code = null;
let probStatement = null;
let probStats = null;
- let probType;
+
let languageDiv = document.querySelector('.leading-4')
? document.querySelector('.leading-4')
: null;
@@ -557,37 +423,19 @@ const loader = setInterval(() => {
? languages[languageDiv.innerText]
: findLanguage();
+ // solution is accepted when the link changes, and a submission is made
+ // basically on a accepted solution we observe a change in href and so we can say solution is accepted
+ // on a wrong ans the link remains same
+
let currentLink = document.location.href;
let solution = currentLink.match(pattern);
- const successTag = document.getElementsByClassName('success__3Ai7');
- const resultState = document.getElementById('result-state');
var success = solution ? true : false;
// check success tag for a normal problem
- if (
- checkElem(successTag) &&
- successTag[0].className === 'success__3Ai7' &&
- successTag[0].innerText.trim() === 'Success'
- ) {
- console.log(successTag[0]);
- success = true;
- probType = NORMAL_PROBLEM;
- }
-
- // check success state for a explore section problem
- else if (
- resultState &&
- resultState.className === 'text-success' &&
- resultState.innerText === 'Accepted'
- ) {
- success = true;
- probType = EXPLORE_SECTION_PROBLEM;
- }
if (success) {
probStatement = parseQuestion().markdown;
probStats = parseStats();
}
-
if (probStatement !== null) {
const problemName = getProblemNameSlug(parseQuestion().title);
if (language !== null) {
@@ -604,7 +452,6 @@ const loader = setInterval(() => {
) {
sha = stats.sha[filePath];
}
-
/* Only create README if not already created */
if (sha === null) {
/* @TODO: Change this setTimeout to Promise */
@@ -618,25 +465,6 @@ const loader = setInterval(() => {
}
});
- /* get the notes and upload it */
- /* only upload notes if there is any */
- notes = getNotesIfAny();
- if (notes.length > 0) {
- setTimeout(function () {
- if (notes != undefined && notes.length != 0) {
- console.log('Create Notes');
- // means we can upload the notes too
- uploadGit(
- btoa(unescape(encodeURIComponent(notes))),
- problemName,
- 'NOTES.md',
- createNotesMsg,
- 'upload',
- );
- }
- }, 500);
- }
-
/* Upload code to Git */
setTimeout(function () {
findCode(
@@ -697,9 +525,18 @@ function insertToAnchorElement(elem) {
target.childNodes[0].prepend(elem);
}
} else {
- if (checkElem(document.getElementsByClassName('action__38Xc'))) {
- target = document.getElementsByClassName('action__38Xc')[0];
- elem.className = 'runcode-wrapper__8rXm';
+ if (
+ checkElem(
+ document.getElementsByClassName(
+ 'ml-auto flex items-center space-x-4',
+ ),
+ )
+ ) {
+ let target = document.getElementsByClassName(
+ 'ml-auto flex items-center space-x-4',
+ )[0];
+ elem.className =
+ 'px-3 py-1.5 font-medium items-center whitespace-nowrap transition-all focus:outline-none inline-flex bg-fill-3 dark:bg-dark-fill-3 hover:bg-fill-2 dark:hover:bg-dark-fill-2 text-label-2 dark:text-dark-label-2 rounded-lg';
if (target.childNodes.length > 0)
target.childNodes[0].prepend(elem);
}
@@ -716,7 +553,7 @@ function startUpload() {
elem.style = 'margin-right: 20px;padding-top: 2px;';
}
elem.innerHTML = ``;
- target = insertToAnchorElement(elem);
+ insertToAnchorElement(elem);
// start the countdown
startUploadCountDown();
} catch (error) {
@@ -731,7 +568,7 @@ function markUploaded() {
elem = document.getElementById('leethub_progress_elem');
if (elem) {
elem.className = '';
- style =
+ let style =
'display: inline-block;transform: rotate(45deg);height:24px;width:12px;border-bottom:7px solid #78b13f;border-right:7px solid #78b13f;';
elem.style = style;
}
@@ -742,7 +579,7 @@ function markUploadFailed() {
elem = document.getElementById('leethub_progress_elem');
if (elem) {
elem.className = '';
- style =
+ let style =
'display: inline-block;transform: rotate(45deg);height:24px;width:12px;border-bottom:7px solid red;border-right:7px solid red;';
elem.style = style;
}
@@ -772,7 +609,6 @@ chrome.storage.local.get('isSync', (data) => {
}
});
-// inject the style
injectStyle();
/* inject css style required for the upload progress feature */
From 647df5d8dc2e9492f3ffcdc4e2c522ff78737f37 Mon Sep 17 00:00:00 2001
From: varun-s22 <93476421+varun-s22@users.noreply.github.com>
Date: Thu, 29 Dec 2022 19:03:23 +0530
Subject: [PATCH 3/3] Fixed repeated uploads
Fixed repeatly uploading of files
Currently one file/solution can be pushed one time.
---
manifest.json | 1 +
scripts/newleetcode.js | 283 ++++++++++++++---------------------------
2 files changed, 100 insertions(+), 184 deletions(-)
diff --git a/manifest.json b/manifest.json
index a283a2dc..38f76d9a 100644
--- a/manifest.json
+++ b/manifest.json
@@ -39,6 +39,7 @@
"https://*.leetcode.cn/*"
],
"js": [
+ "scripts/leetcode.js",
"scripts/newleetcode.js",
"scripts/authorize.js",
"scripts/gfg.js"
diff --git a/scripts/newleetcode.js b/scripts/newleetcode.js
index 8d8b180c..747ed19d 100644
--- a/scripts/newleetcode.js
+++ b/scripts/newleetcode.js
@@ -1,5 +1,5 @@
/* Enum for languages supported by LeetCode. */
-const languages = {
+const programmingLanguages = {
Python: '.py',
Python3: '.py',
'C++': '.cpp',
@@ -22,48 +22,21 @@ const languages = {
};
/* Commit messages */
-const readmeMsg = 'Create README - LeetHub';
-const discussionMsg = 'Prepend discussion post - LeetHub';
-const createNotesMsg = 'Attach NOTES - LeetHub';
+const readMeMsg = 'Create README - LeetHub';
const pattern = /https?:\/\/.*leetcode.com\/problems\/.*\/submissions\/\d*/;
-// problem types
-const NORMAL_PROBLEM = 0;
-const EXPLORE_SECTION_PROBLEM = 1;
-
-/* Difficulty of most recenty submitted question */
-let difficulty = '';
-
/* state of upload for progress */
-let uploadState = { uploading: false };
+let uploadingState = { uploading: false };
let elem;
+let questionDict = {};
/* Util function to check if an element exists */
-function checkElem(elem) {
+function checkElement(elem) {
return elem && elem.length > 0;
}
-/* Get file extension for submission */
-function findLanguage() {
- const tag = [
- ...document.getElementsByClassName(
- 'ant-select-selection-selected-value',
- ),
- ...document.getElementsByClassName('Select-value-label'),
- ];
- if (tag && tag.length > 0) {
- for (let i = 0; i < tag.length; i += 1) {
- const elem = tag[i].textContent;
- if (elem !== undefined && languages[elem] !== undefined) {
- return languages[elem]; // should generate respective file extension
- }
- }
- }
- return null;
-}
-
/* Main function for uploading code to GitHub repo, and callback cb is called if success */
-const upload = (
+const uploadToGit = (
token,
hook,
code,
@@ -107,9 +80,6 @@ const upload = (
// New submission commits twice (README and problem)
if (filename === 'README.md' && sha === null) {
stats.solved += 1;
- stats.easy += difficulty === 'Easy' ? 1 : 0;
- stats.medium += difficulty === 'Medium' ? 1 : 0;
- stats.hard += difficulty === 'Hard' ? 1 : 0;
}
stats.sha[filePath] = updatedSha; // update sha key.
chrome.storage.local.set({ stats }, () => {
@@ -135,7 +105,7 @@ const upload = (
/* Main function for updating code on GitHub Repo */
/* Currently only used for prepending discussion posts to README */
/* callback cb is called on success if it is defined */
-const update = (
+const updateOnGit = (
token,
hook,
addition,
@@ -166,7 +136,7 @@ const update = (
}
/* Write file with new content to GitHub */
- upload(
+ uploadToGit(
token,
hook,
newContent,
@@ -185,7 +155,7 @@ const update = (
xhr.send();
};
-function uploadGit(
+function uploadOnGit(
code,
problemName,
fileName,
@@ -195,11 +165,6 @@ function uploadGit(
cb = undefined,
_diff = undefined,
) {
- // Assign difficulty
- if (_diff && _diff !== undefined) {
- difficulty = _diff.trim();
- }
-
/* Get necessary payload data */
chrome.storage.local.get('leethub_token', (t) => {
const token = t.leethub_token;
@@ -229,7 +194,7 @@ function uploadGit(
if (action === 'upload') {
/* Upload to git. */
- upload(
+ uploadToGit(
token,
hook,
code,
@@ -241,7 +206,7 @@ function uploadGit(
);
} else if (action === 'update') {
/* Update on git */
- update(
+ updateOnGit(
token,
hook,
code,
@@ -261,12 +226,12 @@ function uploadGit(
}
/* Function for finding and parsing the full code. */
-/* - At first find the submission details url. */
-/* - Then send a request for the details page. */
-/* - Finally, parse the code from the html reponse. */
+/* - The solution is available at the same page. */
+/* - Either get the monaco object from the window, or use dom manipulation*/
+/* - Here it gets the code from DOM manipulation */
/* - Also call the callback if available when upload is success */
-function findCode(
- uploadGit,
+function findSubmittedCode(
+ uploadOnGit,
problemName,
fileName,
msg,
@@ -274,8 +239,8 @@ function findCode(
cb = undefined,
) {
let codeUnicoded = null;
- /* Extract only the code */
+ /* Extract only the code */
let codeDiv = document.querySelector('code');
if (!codeDiv) {
return null;
@@ -295,7 +260,7 @@ function findCode(
}
if (codeUnicoded !== null && code !== null) {
setTimeout(function () {
- uploadGit(
+ uploadOnGit(
btoa(unescape(encodeURIComponent(code))),
problemName,
fileName,
@@ -308,7 +273,7 @@ function findCode(
}
}
-function convertToSlug(string) {
+function convertToSlugCase(string) {
const a =
'àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;';
const b =
@@ -326,12 +291,12 @@ function convertToSlug(string) {
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, ''); // Trim - from end of text
}
-function getProblemNameSlug(questionTitle) {
- return convertToSlug(questionTitle);
+function getProblemNameSlugCase(questionTitle) {
+ return convertToSlugCase(questionTitle);
}
/* Parser function for the question and tags */
-function parseQuestion() {
+function getQuestion() {
var questionUrl = window.location.href;
questionUrl = questionUrl.split('submissions')[0];
@@ -340,7 +305,7 @@ function parseQuestion() {
question = question.content;
}
let qArray = question.split(' - ');
- question = qArray.slice(1).join(' ');
+ question = qArray.slice(1).join(' - ');
// Problem title.
let qtitle = qArray[0].trim();
@@ -351,11 +316,11 @@ function parseQuestion() {
}
/* Parser function for time/space stats */
-function parseStats() {
+function getStats() {
let probStats = document.getElementsByClassName(
'text-label-1 dark:text-dark-label-1 ml-2 font-medium',
);
- if (!checkElem(probStats)) {
+ if (!checkElement(probStats)) {
return null;
}
const percentageStats = document.getElementsByClassName(
@@ -363,7 +328,7 @@ function parseStats() {
);
let time = probStats[0].textContent;
let space = probStats[1].textContent;
- if (!checkElem(percentageStats)) {
+ if (!checkElement(percentageStats)) {
return null;
}
let timePercentile = percentageStats[0].textContent;
@@ -372,46 +337,7 @@ function parseStats() {
return `Time: ${time} (${timePercentile}), Space: ${space} (${spacePercentile}) - LeetHub`;
}
-document.addEventListener('click', (event) => {
- const element = event.target;
- const oldPath = window.location.pathname;
-
- /* Act on Post button click */
- /* Complex since "New" button shares many of the same properties as "Post button */
- if (
- element.classList.contains('icon__3Su4') ||
- element.parentElement.classList.contains('icon__3Su4') ||
- element.parentElement.classList.contains(
- 'btn-content-container__214G',
- ) ||
- element.parentElement.classList.contains('header-right__2UzF')
- ) {
- setTimeout(function () {
- /* Only post if post button was clicked and url changed */
- if (
- oldPath !== window.location.pathname &&
- oldPath ===
- window.location.pathname.substring(0, oldPath.length) &&
- !Number.isNaN(window.location.pathname.charAt(oldPath.length))
- ) {
- const date = new Date();
- const currentDate = `${date.getDate()}/${date.getMonth()}/${date.getFullYear()} at ${date.getHours()}:${date.getMinutes()}`;
- const addition = `[Discussion Post (created on ${currentDate})](${window.location}) \n`;
- const problemName = window.location.pathname.split('/')[2]; // must be true.
-
- uploadGit(
- addition,
- problemName,
- 'README.md',
- discussionMsg,
- 'update',
- );
- }
- }, 1000);
- }
-});
-
-const loader = setInterval(() => {
+const mainFunction = setInterval(() => {
let probStatement = null;
let probStats = null;
@@ -420,8 +346,8 @@ const loader = setInterval(() => {
: null;
const language = languageDiv
- ? languages[languageDiv.innerText]
- : findLanguage();
+ ? programmingLanguages[languageDiv.innerText]
+ : null;
// solution is accepted when the link changes, and a submission is made
// basically on a accepted solution we observe a change in href and so we can say solution is accepted
@@ -433,14 +359,22 @@ const loader = setInterval(() => {
var success = solution ? true : false;
// check success tag for a normal problem
if (success) {
- probStatement = parseQuestion().markdown;
- probStats = parseStats();
+ probStatement = getQuestion().markdown;
+ probStats = getStats();
}
if (probStatement !== null) {
- const problemName = getProblemNameSlug(parseQuestion().title);
+ const problemName = getProblemNameSlugCase(getQuestion().title);
+ let filePath = problemName + problemName + language;
+ let readmeKey = language + problemName;
+ if (
+ questionDict[filePath] !== undefined ||
+ questionDict[readmeKey] !== undefined
+ ) {
+ return null;
+ }
if (language !== null) {
// start upload indicator here
- startUpload();
+ startUploading();
chrome.storage.local.get('stats', (s) => {
const { stats } = s;
const filePath = problemName + problemName + language;
@@ -455,96 +389,77 @@ const loader = setInterval(() => {
/* Only create README if not already created */
if (sha === null) {
/* @TODO: Change this setTimeout to Promise */
- uploadGit(
- btoa(unescape(encodeURIComponent(probStatement))),
- problemName,
- 'README.md',
- readmeMsg,
- 'upload',
- );
+ if (questionDict[readmeKey] === undefined) {
+ uploadOnGit(
+ btoa(unescape(encodeURIComponent(probStatement))),
+ problemName,
+ 'README.md',
+ readMeMsg,
+ 'upload',
+ );
+ questionDict[readmeKey] = Date.now();
+ }
}
});
-
- /* Upload code to Git */
- setTimeout(function () {
- findCode(
- uploadGit,
- problemName,
- problemName + language,
- probStats,
- 'upload',
- // callback is called when the code upload to git is a success
- () => {
- if (uploadState['countdown'])
- clearTimeout(uploadState['countdown']);
- delete uploadState['countdown'];
- uploadState.uploading = false;
- markUploaded();
- },
- ); // Encode `code` to base64
- }, 1000);
+ if (questionDict[filePath] === undefined) {
+ /* Upload code to Git */
+ setTimeout(function () {
+ findSubmittedCode(
+ uploadOnGit,
+ problemName,
+ problemName + language,
+ probStats,
+ 'upload',
+ // callback is called when the code upload to git is a success
+ () => {
+ if (uploadingState['countdown'])
+ clearTimeout(uploadingState['countdown']);
+ delete uploadingState['countdown'];
+ uploadingState.uploading = false;
+ markTheUploaded();
+ },
+ ); // Encode `code` to base64
+ questionDict[filePath] = Date.now();
+ }, 1000);
+ }
}
}
}, 1000);
/* Since we dont yet have callbacks/promises that helps to find out if things went bad */
/* we will start 10 seconds counter and even after that upload is not complete, then we conclude its failed */
-function startUploadCountDown() {
- uploadState.uploading = true;
- uploadState['countdown'] = setTimeout(() => {
- if ((uploadState.uploading = true)) {
+function startUploadCountdown() {
+ uploadingState.uploading = true;
+ uploadingState['countdown'] = setTimeout(() => {
+ if ((uploadingState.uploading = true)) {
// still uploading, then it failed
- uploadState.uploading = false;
- markUploadFailed();
+ uploadingState.uploading = false;
+ markUploadFail();
}
}, 10000);
}
/* we will need specific anchor element that is specific to the page you are in Eg. Explore */
-function insertToAnchorElement(elem) {
- if (document.URL.startsWith('https://leetcode.com/explore/')) {
- // means we are in explore page
- action = document.getElementsByClassName('action');
- if (
- checkElem(action) &&
- checkElem(action[0].getElementsByClassName('row')) &&
- checkElem(
- action[0]
- .getElementsByClassName('row')[0]
- .getElementsByClassName('col-sm-6'),
- ) &&
- action[0]
- .getElementsByClassName('row')[0]
- .getElementsByClassName('col-sm-6').length > 1
- ) {
- target = action[0]
- .getElementsByClassName('row')[0]
- .getElementsByClassName('col-sm-6')[1];
- elem.className = 'pull-left';
- if (target.childNodes.length > 0)
- target.childNodes[0].prepend(elem);
- }
- } else {
- if (
- checkElem(
- document.getElementsByClassName(
- 'ml-auto flex items-center space-x-4',
- ),
- )
- ) {
- let target = document.getElementsByClassName(
+function insertToAnchor(elem) {
+ if (
+ checkElement(
+ document.getElementsByClassName(
'ml-auto flex items-center space-x-4',
- )[0];
- elem.className =
- 'px-3 py-1.5 font-medium items-center whitespace-nowrap transition-all focus:outline-none inline-flex bg-fill-3 dark:bg-dark-fill-3 hover:bg-fill-2 dark:hover:bg-dark-fill-2 text-label-2 dark:text-dark-label-2 rounded-lg';
- if (target.childNodes.length > 0)
- target.childNodes[0].prepend(elem);
- }
+ ),
+ )
+ ) {
+ let target = document.getElementsByClassName(
+ 'ml-auto flex items-center space-x-4',
+ )[0];
+ elem.className =
+ 'px-3 py-1.5 font-medium items-center whitespace-nowrap transition-all focus:outline-none inline-flex bg-fill-3 dark:bg-dark-fill-3 hover:bg-fill-2 dark:hover:bg-dark-fill-2 text-label-2 dark:text-dark-label-2 rounded-lg';
+ if (target.childNodes.length > 0)
+ target.childNodes[0].prepend(elem);
}
}
/* start upload will inject a spinner on left side to the "Run Code" button */
-function startUpload() {
+function startUploading() {
try {
elem = document.getElementById('leethub_progress_anchor_element');
if (!elem) {
@@ -553,9 +468,9 @@ function startUpload() {
elem.style = 'margin-right: 20px;padding-top: 2px;';
}
elem.innerHTML = ``;
- insertToAnchorElement(elem);
+ insertToAnchor(elem);
// start the countdown
- startUploadCountDown();
+ startUploadCountdown();
} catch (error) {
// generic exception handler for time being so that existing feature doesnt break but
// error gets logged
@@ -564,7 +479,7 @@ function startUpload() {
}
/* This will create a tick mark before "Run Code" button signalling LeetHub has done its job */
-function markUploaded() {
+function markTheUploaded() {
elem = document.getElementById('leethub_progress_elem');
if (elem) {
elem.className = '';
@@ -575,7 +490,7 @@ function markUploaded() {
}
/* This will create a failed tick mark before "Run Code" button signalling that upload failed */
-function markUploadFailed() {
+function markUploadFail() {
elem = document.getElementById('leethub_progress_elem');
if (elem) {
elem.className = '';
@@ -609,10 +524,10 @@ chrome.storage.local.get('isSync', (data) => {
}
});
-injectStyle();
+injectCode();
/* inject css style required for the upload progress feature */
-function injectStyle() {
+function injectCode() {
const style = document.createElement('style');
style.textContent =
'.leethub_progress {pointer-events: none;width: 2.0em;height: 2.0em;border: 0.4em solid transparent;border-color: #eee;border-top-color: #3E67EC;border-radius: 50%;animation: loadingspin 1s linear infinite;} @keyframes loadingspin { 100% { transform: rotate(360deg) }}';