ipadやiphone用に、画面にログを出力する。console.log() の代わりに screenLog() で利用する。
As of
This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/577436/1820903/Screen%20Display%20Log.js
// ==UserScript==
// @name Screen Display Log
// @namespace http://tampermonkey.net/
// @version 1.1
// @description ipadやiphone用に、画面にログを出力する。console.log() の代わりに screenLog() で利用する。
// @author YourName
// @grant none
// ==/UserScript==
/**
* 画面端にデバッグ用UIを表示するクラス
*/
class ScreenLogger {
constructor() {
this.id = 'tm-debug-console';
this.container = null;
this.logArea = null;
this._setup();
}
async _setup() {
// bodyが読み込まれるまで待機
while (!document.body) {
await new Promise(r => setTimeout(r, 100));
}
if (document.getElementById(this.id)) return;
this._injectStyles();
this._createUI();
}
_injectStyles() {
const style = document.createElement('style');
style.textContent = `
#${this.id} { position: fixed; bottom: 10px; right: 10px; width: 280px; max-height: 250px; background-color: rgba(0, 0, 0, 0.85); color: #00ff00; font-size: 11px; font-family: monospace; padding: 5px; border-radius: 5px; overflow-y: auto; z-index: 999999; pointer-events: auto; border: 1px solid #444; box-shadow: 0 0 10px rgba(0,0,0,0.5); }
#${this.id} .tm-header { border-bottom: 1px solid #444; margin-bottom: 5px; padding-bottom: 3px; display: flex; justify-content: space-between; align-items: center; }
#${this.id} .tm-header b { color: #fff; }
#${this.id} button { font-size: 9px; cursor: pointer; margin-left: 4px; }
#${this.id} .tm-log-area { display: block; }
#${this.id} .tm-line { border-bottom: 1px solid #222; padding: 2px 0; white-space: pre-wrap; word-break: break-all; }
#${this.id}.minimized { height: 25px; overflow: hidden; }
#${this.id}.minimized .tm-log-area { display: none; }
`;
document.head.appendChild(style);
}
_createUI() {
this.container = document.createElement('div');
this.container.id = this.id;
this.container.innerHTML = `
<div class="tm-header">
<span><b>[DEBUG]</b></span>
<div>
<button id="tm-clear-log">Clear</button>
<button id="tm-toggle-log">Min</button>
</div>
</div>
<div class="tm-log-area"></div>
`;
this.logArea = this.container.querySelector('.tm-log-area');
document.body.appendChild(this.container);
this.container.querySelector('#tm-clear-log').onclick = () => this.clear();
this.container.querySelector('#tm-toggle-log').onclick = (e) => this._toggle(e.target);
}
_toggle(btn) {
const isMinimized = this.container.classList.toggle('minimized');
btn.innerText = isMinimized ? 'Max' : 'Min';
}
clear() {
if (this.logArea) this.logArea.innerHTML = '';
}
_format(arg) {
if (arg === null) return 'null';
if (arg === undefined) return 'undefined';
if (arg instanceof HTMLElement) {
const id = arg.id ? `#${arg.id}` : '';
const classes = arg.className ? `.${Array.from(arg.classList).join('.')}` : '';
return `<${arg.tagName.toLowerCase()}${id}${classes}>`;
}
if (typeof arg === 'object') {
try { return JSON.stringify(arg); } catch (e) { return String(arg); }
}
return String(arg);
}
log(...args) {
if (!this.logArea) return; // UIがまだ作られていない場合は無視
const msg = args.map(arg => this._format(arg)).join(' ');
const line = document.createElement('div');
line.className = 'tm-line';
line.innerText = `> ${msg}`;
this.logArea.appendChild(line);
this.container.scrollTop = this.container.scrollHeight;
}
}
// グローバルスコープ(window)に公開する
window.screenLog = (function() {
const logger = new ScreenLogger();
return logger.log.bind(logger);
})();