您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
AtCoder の解説コードなどをフォーマットできるようにします.
当前为
- // ==UserScript==
- // @name AtCoder Formatter
- // @name:en AtCoder Formatter
- // @namespace
- // @version 1.4.0
- // @description AtCoder の解説コードなどをフォーマットできるようにします.
- // @description:en Add formatting buttons to source codes on AtCoder.
- // @author kichi2004
- // @match https://atcoder.jp/contests/*
- // @grant none
- // @namespace kichi2004.jp
- // @license MIT
- // ==/UserScript==
- 'use strict';
- async function request(code, lang) {
- const res = await fetch(`https://formatter.api.kichi2004.jp/format?lang=${lang}`, {
- body: code,
- method: 'POST'
- })
- if (!res.ok) {
- alert('Formatting Request Failed!')
- return
- }
- const json = await res.json()
- if (json['status'] === 'error') {
- alert('Formatting Error!\n' + json['error'])
- return
- }
- return json['result']
- }
- function createButtons(className, id) {
- return `
- <div class="btn-group" role="group">
- <button type="button" class="btn ${className} btn-sm" title="C/C++ のソースコードをフォーマット" id="${id}-fmt-cpp">
- C/C++
- </button>
- <button type="button" class="btn ${className} btn-sm" title="Python のソースコードをフォーマット" id="${id}-fmt-py">
- Python
- </button>
- <button type="button" class="btn ${className} btn-sm" title="C# のソースコードをフォーマット" id="${id}-fmt-cs">
- C#
- </button>
- </div>`;
- }
- const SOURCE_ID = 'source'
- ;(async function () {
- const showModal = (id, formatInner) => {
- if (!document.getElementById(`modal-${id}-format-warning`)) {
- document.createht
- document.body.insertAdjacentHTML('afterbegin', `
- <div id="modal-${id}-format-warning" class="modal fade" tabindex="-1" role="dialog">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
- <h4 class="modal-title">フォーマットの注意</h4>
- </div>
- <div class="modal-body">
- <p>このコンテストはまだ終了していません。</p>
- <p>フォーマットを行うとソースコードが外部に送信され、スクリプトの作成者が閲覧可能な状態になります。</p>
- <p>まだ公開されていないコンテストではフォーマットを行わないでください。</p>
- </div>
- <div class="modal-footer">
- <button class="btn btn-warning" id="${id}-force-format">フォーマットする</button>
- <button class="btn btn-success" id="${id}-cancel">キャンセル</button>
- </div>
- </div>
- </div>
- </div>
- `)
- document.getElementById(`${id}-force-format`).addEventListener('click', async () => await formatInner(true))
- document.getElementById(`${id}-cancel`).addEventListener('click', () => removeModal(id))
- }
- $(`#modal-${id}-format-warning`).modal('show')
- }
- const removeModal = (id) => {
- const modal = $(`#modal-${id}-format-warning`)
- modal.modal('hide')
- }
- const formatCode = async (event, pre, id, lang) => {
- const formatInner = async (modal = false) => {
- if (modal) removeModal(id)
- event.target.disabled = true
- const data = document.getElementById(id)
- const result = await request(data.innerText, lang, event)
- event.target.disabled = false
- if (!result) return
- const nextPre = document.createElement('pre')
- nextPre.textContent = result
- nextPre.classList.add('prettyprint', `lang-${lang}`, 'linenums')
- pre.before(nextPre)
- const preId = pre.id
- pre.remove()
- if (preId) {
- nextPre.id = preId
- }
- data.textContent = result
- PR.prettyPrint()
- }
- const finished = endTime.toDate() < new Date()
- if (finished) {
- await formatInner()
- return
- }
- showModal(id, formatInner)
- }
- const formatTextArea = async (event, lang) => {
- const formatInner = async (modal = false) => {
- if (modal) removeModal(SOURCE_ID)
- event.target.disabled = true
- const sw = $(".editor-buttons > p:nth-child(2) > button")
- const active = sw.attr('aria-pressed') === 'true'
- if (!active) sw.trigger('click')
- const textarea = sourceCodeDiv.children('textarea.plain-textarea')
- const code = textarea.val()
- const result = await request(code, lang, event)
- event.target.disabled = false
- if (!result) {
- if (!active) sw.trigger('click')
- return
- }
- textarea.val(result)
- if (!active) sw.trigger('click')
- }
- const finished = endTime.toDate() < new Date()
- if (finished) {
- await formatInner()
- return
- }
- showModal(SOURCE_ID, formatInner)
- }
- const buttonClass = endTime.toDate() < new Date() ? 'btn-info' : 'btn-danger'
- for (const pre of document.getElementsByClassName('prettyprint')) {
- const next = pre.nextElementSibling
- if (next.className !== 'source-code-for-copy') continue
- const id = next.id
- let adding = pre.previousElementSibling
- while (adding.className === 'div-btn-copy')
- adding = adding.previousElementSibling
- adding.insertAdjacentHTML('afterend',createButtons(buttonClass, id))
- for (const lang of ['cpp', 'py', 'cs']) {
- document.getElementById(`${id}-fmt-${lang}`)
- .addEventListener('click', async (e) => await formatCode(e, pre, id, lang))
- }
- }
- const sourceCodeDiv = $('#sourceCode')
- if (!sourceCodeDiv) return
- $('.editor-buttons')[0].insertAdjacentHTML('beforeend', createButtons(buttonClass, SOURCE_ID))
- for (const lang of ['cpp', 'py', 'cs']) {
- document.getElementById(`source-fmt-${lang}`)
- .addEventListener('click', async (e) => await formatTextArea(e, lang))
- }
- })()