From a964235e5f446ff2867d2ab012f3fd05c6307b1d Mon Sep 17 00:00:00 2001 From: conlacda Date: Sun, 29 Dec 2024 11:44:14 +0900 Subject: [PATCH] add copy button to tasks_print --- .../tests/copy_button_on_tasks_print.spec.ts | 43 +++++++++++++++++++ .../chrome-extension/manifest.json | 8 ++++ .../scripts/tasks_print/main.js | 37 ++++++++++++++++ .../chrome-extension/scripts/testcase/main.js | 2 +- 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 browser-extension/chrome-extension-test/tests/copy_button_on_tasks_print.spec.ts create mode 100644 browser-extension/chrome-extension/scripts/tasks_print/main.js diff --git a/browser-extension/chrome-extension-test/tests/copy_button_on_tasks_print.spec.ts b/browser-extension/chrome-extension-test/tests/copy_button_on_tasks_print.spec.ts new file mode 100644 index 0000000..3e9adbb --- /dev/null +++ b/browser-extension/chrome-extension-test/tests/copy_button_on_tasks_print.spec.ts @@ -0,0 +1,43 @@ +import {test, expect} from '../fixtures'; +import {Page, Locator} from "@playwright/test"; + +require('dotenv').config({path: './.env'}); + +test.describe.configure({mode: 'serial'}); + +let page: Page; + +test.beforeAll(async ({context}) => { + page = await context.newPage(); + await page.goto('https://atcoder.jp/contests/abc386/tasks_print'); +}); + +test.afterAll(async () => { + await page.close(); +}); + +test('Check copy buttons are added', async () => { + const copyButtons = page.locator('span.btn-copy'); + await expect(copyButtons).toHaveCount(52); +}); + +test('Check clipboard after copying', async () => { + const copyButtons = page.locator('span.btn-copy'); + // First button + await copyButtons.nth(0).click(); + let copiedText = await page.evaluate(() => navigator.clipboard.readText()); + expect(copiedText.replace(/\r\n/g, '')).toBe('7 7 7 1'); + + // 28th button + await copyButtons.nth(28).click(); + copiedText = await page.evaluate(() => navigator.clipboard.readText()); + expect(copiedText.replace(/\r/g, '')).toBe('4 3\n' + + '4 1 B\n' + + '3 2 W\n' + + '1 3 B\n'); + + // Last button + await copyButtons.nth(51).click(); + copiedText = await page.evaluate(() => navigator.clipboard.readText()); + expect(copiedText.replace(/\r\n/g, '')).toBe('707081320'); +}); diff --git a/browser-extension/chrome-extension/manifest.json b/browser-extension/chrome-extension/manifest.json index a6de53c..7c36e7d 100644 --- a/browser-extension/chrome-extension/manifest.json +++ b/browser-extension/chrome-extension/manifest.json @@ -110,6 +110,14 @@ ], "run_at": "document_idle", "world": "MAIN" + }, + { + "js": [ + "scripts/tasks_print/main.js" + ], + "matches": [ + "*://atcoder.jp/contests/*/tasks_print" + ] } ] } diff --git a/browser-extension/chrome-extension/scripts/tasks_print/main.js b/browser-extension/chrome-extension/scripts/tasks_print/main.js new file mode 100644 index 0000000..98b8653 --- /dev/null +++ b/browser-extension/chrome-extension/scripts/tasks_print/main.js @@ -0,0 +1,37 @@ +const isVisible = (element) => { + return element.offsetWidth > 0 && + element.offsetHeight > 0 && + window.getComputedStyle(element).visibility !== 'hidden' + && window.getComputedStyle(element).display !== 'none'; +} + +let index = 0; +while (true) { + const taskStatement = document.getElementById('task-statement'); + if (taskStatement) { + taskStatement.id = `task-statement-${index}`; + index++; + } else break; +} + +for (let i = 0; i < index; i++) { + const taskStatement = document.getElementById(`task-statement-${i}`); + const divsAfterIODiv = taskStatement.querySelectorAll('div.io-style ~ div.part'); + const ioDivs = Array.from(divsAfterIODiv).filter(isVisible); + + for (const div of ioDivs) { + const button = (new DOMParser()).parseFromString(`Copy`, "text/html").body.firstChild; + var h3Element = div.querySelector('h3'); + h3Element.insertAdjacentElement('beforeend', button); + const pre = h3Element.nextElementSibling; + button.addEventListener('click', function () { + copyToClipboard(pre.textContent).then(() => { + button.textContent = 'Copied'; + setTimeout(() => { + button.textContent = 'Copy'; + button.blur(); + }, 500); + }); + }); + } +} diff --git a/browser-extension/chrome-extension/scripts/testcase/main.js b/browser-extension/chrome-extension/scripts/testcase/main.js index 2e3b0d1..f67db54 100644 --- a/browser-extension/chrome-extension/scripts/testcase/main.js +++ b/browser-extension/chrome-extension/scripts/testcase/main.js @@ -8,7 +8,7 @@ const copyButton = $('span[data-toggle="tooltip"]:visible').first(); if (allTestCasesSz === 0) return; - const downloadButton = (new DOMParser()).parseFromString(``, "text/html").body.children[0]; + const downloadButton = (new DOMParser()).parseFromString(``, "text/html").body.firstChild; document.querySelector('span.h2').appendChild(downloadButton); downloadButton.onclick = async () => { downloadButton.disabled = true;