jsファイルにコードを書かないと簡単なサンプルも実行できない。
勿論、そんなものはオンラインにあるけど、そういうところにソースをパリッと貼り付けるのはご法度なケースも多いので・・・
パパッとjavascriptのサンプルをローカルなHTMLで実行するサンプルを作ってみた。
但し、new Functionからはグローバルな変数が見えてしまう。
それだけなら特に危なくないけど
某MS操縦士のセリフ:俺を踏み台にしたぁ~~~
なんてコードを書かれても不思議ではない碌でもない世の中なので、
ソースだけ公開。
<DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>javascriptを実行させるサンプル</title>
<link href="jstest.css" media="all" rel="stylesheet" type="text/css" />
<script src="createelement.js"></script>
<script src="download.js"></script>
<script src="jstest.js"></script>
<link href="loader.css" media="all" rel="stylesheet" type="text/css" />
<script src="loader.js"></script>
</head>
<body>
<!-- loader begin -->
<div id="js-loader" class="loader">
<p>***</p>
<p id="js-loader-text"></p>
<p>***</p>
</div>
<!-- loader end -->
<textarea class="jsText" id="jsText1" scrolling="auto">
// sample code
return new Promise((resolve, reject) => {
let result = new Array(10);
for (let index = 0; index < 10; index++) {
result[index]=index + 1;
}
console.log(result); console.log(10);
console.log('aaaaaaaaaaaaaa');
console.log({log: 'data=> result=data' });
resolve();
});
</textarea><br />
<button type="button" id="executeJsText">実行</button><br />
<div class="status" id="status"></div><br />
<textarea class="jsResult" id="jsResult1" scrolling="auto"></textarea><br />
<button type="button" id="downloadJsText">javaScriptダウンロード</button><br />
<button type="button" id="downloadResult">結果ダウンロード</button><br />
</body>
</html>
@charset "UTF-8";
textarea.jsText {
width: 95%;
/* 親要素の幅と合わせる */
height: 200px;
resize: both;
border: 2mm ridge rgba(211, 220, 50, .6);
}
textarea.jsResult {
width: 95%;
/* 親要素の幅と合わせる */
height: 100px;
resize: both;
border: 2mm ridge rgba(211, 220, 50, .6);
}
let CRLF = '\r\n';
window.addEventListener('load', () => init());
/**
* 初期化処理
*/
const init = () => {
// ボタンクリックイベントの登録
document.querySelector('#downloadJsText').addEventListener('click', () => downloadText('jsText1'));
document.querySelector('#downloadResult').addEventListener('click', () => downloadText('jsResult1'));
document.querySelector('#executeJsText').addEventListener('click', () => dexecuteJsText('jsText1', 'jsResult1'));
loaderClose();
};
/**
* サンプルをエンコーディングしたファイルをダウンロードする
*/
const downloadText = async (target) => {
try {
loaderOpen();
try {
let dateBegin = Date.now();
displayStatus(`${target}ダウンロード処理中`);
let jsText = document.querySelector(`#${target}`).value;
download(jsText, `${target}.js`, "text/plan");
displayStatus(`${target}ダウンロード完了。処理時間:${dateDateBetween(dateBegin, Date.now())}`);
} catch (ex) {
alert(`${target}ダウンロード異常終了${CRLF}${ex}`);
}
loaderClose();
} catch (ex) {
alert(ex);
}
};
/**
* 実行する
* @param {*} jsText
* @param {*} jsResult
*/
const dexecuteJsText = (jsText, jsResult) => {
let jsTextElmText = document.querySelector(`#${jsText}`).value;
let jsResultElm = document.querySelector(`#${jsResult} `);
let dateBegin = Date.now();
try {
loaderOpen();
try {
displayStatus(`${jsText} 実行処理中`);
let func = new Function('console', jsTextElmText);
let result = [];
let radix = 10;
let rc = func({
log: (data) => {
if (data === undefined) {
data = 'undefined';
}
if (data === null) {
data = 'null';
}
switch (typeof data) {
case 'object':
data = JSON.stringify(data);
break;
case 'string':
break;
default:
data = data.toString(radix);
break;
}
result.push(data);
}
});
new Promise((resolve, reject) => {
if (rc instanceof Promise) {
displayStatus(`${jsText} 実行中 Promise.then待ち`);
rc.then(() => {
resolve(result);
});
} else {
resolve(result);
}
}).then((result) => {
jsResultElm.innerHTML = result.join(CRLF);
displayStatus(`${jsText} 実行完了。処理時間:${dateDateBetween(dateBegin, Date.now())} `);
});
} catch (ex) {
displayStatus(`${jsText} 実行異常終了。処理時間:${dateDateBetween(dateBegin, Date.now())}${CRLF}${ex} `);
}
loaderClose();
} catch (ex) {
alert(ex);
}
};
/**
* ステータスを表示する
* @param {string} text
*/
const displayStatus = (text) => {
let divStatus = document.querySelector('#status');
divStatus.innerHTML = text;
let divLoading = document.querySelector('#js-loader-text');
divLoading.innerHTML = text;
};
/**
* 時刻差のテキストを作成する
* @param {Date} dateBegin
* @param {Date} dateEnd
* @returns
*/
const dateDateBetween = (dateBegin, dateEnd) => {
return `${(dateEnd - dateBegin) / 1000} 秒`
};
createelement.js
download.js
loader.css
loader.js
は先の記事
デスクトップに貼ったJSからSJISのCSVをダウンロードさせてみる【その後】のサンプル
と同じなので割愛。
ミソはjsソース中に
console.log(result);
と書かれたらどうやって取り出すか?
である。
今回は
let result = "";
let func = new Function( 'console', jsテキスト);☚jsテキストの処理に対してパラメータ'console'を宣言
func({log: (data) => ☚{...}内がconsoleオブジェクトとして扱われ、result変数にセットされる。
これでjsテキストの中でconsole.logメソッドがそれっぽく動き出す。
jsコードがwindowやdocumentを直接参照するのが嫌なら
let func = new Function( 'console', 'window', 'document', ..., jsテキスト);
func(
{log: (data) => result.push(data);},
{console: (data) => xxxx;},
{body: (data) => xxxx;},
);
とパラメータを追加し、見せたい情報を渡してサンドバック風にできるだろう。