恐怖!Edgeで全角入力時に重複して文字入力されてしまう問題(IME,Edge,Chrome)
問題
IMEで全角文字入力→確定せずに別の場所にフォーカスを移すと、文字が重複して入力される。
文字面だとわかりづらいので、下記のGIFを見てもらったほうが早い。
「あああ」 の入力が二倍になって「ああああああ」になっている。

この問題は、下記テストページで体験できるようにしてある。
この恐怖を体感してみてほしい。
発生する条件
どうも下記の状態をすべて満たすと発生する模様
- ブラウザが Edge Chrome (=つまりChroniumのブラウザ。Firefoxだと発生しない)
- IMEが Microsoft IME (Google IMEだと発生しない。)
- 入力欄(input type=textとか)で、フォーカス時に入力欄を全選択している。
jsとHTMLだと下記のような感じ。

- 全角入力の変換確定前に、別の入力欄にフォーカスを移動させる
- フォーカスを全選択していても、一度全選択を解除した後だと発生しない。
なぜ発生するのか
Microsoft IMEのバグ?(相性が悪い?)の模様。
フォーカス時に全選択する、というUIがあまりないことが原因で、あまりネットにも情報がない。
解決方法
フォーカス時の全選択をやめてしまう。これで100点取れる。
該当項目が半角入力のみを想定されているのであれば、
inputmodeを指定して、フォーカス時に半角入力モードになるようにしてあげれば、 発生確率は下げられる。
※ご参考URLの 全選択解除→時間をおいて再度全選択、の方法だと解消されなかった。
ほかの解決方法があるなら、教えてください
ご参考
input入力中に変換未確定の状態でフォーカス移動すると文字が二重入力される
Chrome(Windows版)でinput要素への入力中に変換未確定の状態でフォーカス移動すると文字列が二重入力される件について|さとう
余談(GIF動画)
GIFを撮影する方法ですが、
Win11 の Snipping Tool で動画撮影 → AdobeのサイトでGIF化 して作っています。

ExcelからINSERT,UPDATEのSQLつくるの面倒だからWEBツールつくった
結論
これつくった
使い方
ExcelからINSERT・UPDATEしたいデータ(表)を
Ctrl+A → Ctrl+C で表をコピー
↓
このツールの「TSVテキスト」というところに張り付ける
↓
SQLができる
暇なら後日使い方GIFでもつけておこう。
習うより慣れてくれ。もともと個人で使う用として作ったんや。
ポイント
セキュリティ意識高いから、JavaScript(フロントエンド)だけで動く。
サーバーへの通信は発生しないから、機密情報もガンガン入力して問題ないはず。
エッチな広告とかも出ない。
それでも心配なら、GitHubからソースDLして、各自のローカルで動かしてね。
背景
Excelでメンテ用データつくるやん?
これを数式をコネコネしてSQLつくろうとするやん?
めっちゃしんどい数式ができる+汎用性ないやん?
作った。
レガシー環境のJavaで戦うための、SQL→Java変換器
背景
Javaで、複数行のSQLを、ソースに埋め込みたい場合があると思う。
Java15 からは テキストブロックという機能で、 複数行で文字列定数を定義するのが簡単にできるので、 あまり苦労しない(はず)
[Java]テキストブロックってかなり便利だね #java17 - Qiita
これができない、 古いJava環境で開発せざるをえない場合に使える、 JavaScriptで稼働するツールを作った。
つくったもの
情報漏洩にうるさい方々のために、HTML+CSS+JavaScriptのみで動作している。

使い方
select id from hogehoge where id='123';
を張り付けると
StringBuffer sb = new StringBuffer(); sb.append("select "); sb.append(" id "); sb.append("from hogehoge "); sb.append("where id='123'; ");
が出力される。
逆も用意している。
変数名はデフォルトsbにしているが、好きに変えられる。
技術詳細
今のJavaはどうか知らないが、昔のJavaは 文字列連結を
String hoge = "a" + "b" + "c";
のように、+を使って連結すると、すごく遅いと言われていた。
解決方法としては、 StringBufferを使えと言われていたので、 それを踏襲している。
PHP+SQLiteで、UPDATE文を実行すると、エラーを吐かずになぜか0 がセットされる
総括
SQLiteにおいて、SQLの書き方によっては文法エラーにならずに、 意図しない値がDBにセットされる模様。
※見解が間違っていたらごめんなさいm( "m)
背景
下記のようなPHP関数を実行する。
実行結果としては、特定IDのレコードのカラム値がUPDATEされてほしい。
function update($id, $manual_label1, $manual_label2)
{
var_dump($id, $manual_label1, $manual_label2);
$pdo = new PDO(DB_DSN);
$pdo->beginTransaction();
$sql = "
update TRAINING set
MANUAL_LABEL1 = :manual_label1
and MANUAL_LABEL2 = :manual_label2
where ID = :id
";
$stmt = $pdo->prepare($sql);
$stmt->execute(
array(
":manual_label1" => $manual_label1,
":manual_label2" => $manual_label2,
":id" => $id,
)
);
$pdo->commit();
return;
}
問題
- 処理は成功する(エラーは出力されない)
- 意図した値でUPDATEされない。 MANUAL_LABEL1 に 0 が入る。
原因
聡明な方ならお気づきだろうが、SQLが間違っている。
andではなく , でしたと。
typoなんだ許してくれ
誤
update TRAINING set MANUAL_LABEL1 = :manual_label1 and MANUAL_LABEL2 = :manual_label2 where ID = :id
正
update TRAINING set MANUAL_LABEL1 = :manual_label1 ,MANUAL_LABEL2 = :manual_label2 where ID = :id
というよりちゃんとロールバックまでやるべきだが、 どうも例外吐いてすらいなさそう
try {
$pdo = new PDO(DB_DSN);
$pdo->beginTransaction();
$sql = "
update TRAINING set
MANUAL_LABEL1 = :manual_label1
,MANUAL_LABEL2 = :manual_label2
where ID = :id
";
$stmt = $pdo->prepare($sql);
$stmt->execute(
array(
":manual_label1" => $manual_label1,
":manual_label2" => $manual_label2,
":id" => $id,
)
);
$pdo->commit();
} catch (PDOException $e) {
$pdo->rollBack();
}
感想
SQL文法エラーで落ちてくれないですかね・・・
proxy環境下において、Python requests がグローバルIP制限に引っかったときのメモ
結論を先に書くと、「プロキシ用pacファイルまでちゃんと意識してコード書いてる?」
問題
プロキシ環境化において、Python requestsパッケージを用いて、APIを叩きたい
前提として、
- API、管理画面はグローバルIP制限を施している
- APIからレスポンスは返ってくるが、「許可されていないIPです」と出る
- ブラウザ側から管理画面には普通にアクセスできる(=インフラ的な設定・申請は問題ないはず)
- IP制限を外すと、PythonからAPIは叩ける
コード例
import requests response = requests.get('APIのURL', proxies={ 'http' : 'http://example.com' 'https' : 'http://example.com' })
GIP制限外すとつながるので、コードにも問題はなさそう。
原因
OS側でpacファイルが指定されていた。 そのpacファイル内にて、アクセス先のサイトに応じて 使用するプロキシサーバーを振り分けていることが判明。
私のコードでは、通常利用するプロキシサーバーを指定しており、 そのプロキシサーバーのIPが可変だったため、 グローバルIPの制限にひっかかっていた。
対策
方法1 PACファイル内部を見て、アクセスしようとしているAPIのURLが どのプロキシサーバーを使うかを確認し、そのプロキシサーバーを記載する
方法2 pypacというパッケージがあるので、 プロキシサーバーではなく、 PACファイルを指定→pacファイル側でプロキシサーバーを指定するようにする
使い方は下記参照
PyPAC: Proxy auto-config for Python — PyPAC 0.16.3 documentation
PACファイル確認方法の一例
win11の例



コントロールパネル→インターネットオプションとかからでも確認できると思いますよ。
総括
プロキシと言われたときには、プロキシサーバーだけではなく、 その手前の.pacファイルまで意識しましょう。
終わり
WYSIWYGエディタをWEBページに埋め込めるライブラリ比較
背景
WEBページの管理画面でHTMLを直接書かせたくないので、 WYSIWYGエディタを埋め込みたいと思った。
※WYSIWYGエディタの例(はてなブログの記事改廃画面)↓

javaScriptでいい感じのあるだろうと思ってググると案の定存在した。
調査比較
前提:
- 無料
- HTML+CSS+JSで埋め込める
三つほど見つかったので、触ってみた特徴を記載していく
一応簡単に実装もしたので、下記に配置しておく。
作成した比較サイト
ソース
gologius.github.io/test/test_WYSIWYG at master · gologius/gologius.github.io · GitHub
以下個人の感想。上記の比較サイトなども使って、自分にベストなものを選んでほしい。
trix.js
- ○ 埋め込むだけなら一番楽。 jsも書かずに済むし、input への反映も楽。すでにinputタグがあるなら、既存コードにすぐ埋め込める
- ○ undo redo ボタンがある
- × 文字サイズとか色が設定できない
- × 設定APIなどがないので、カスタマイズができない?
quill
- ○ 機能豊富。文字の色なども変えられる。画像もbase64形式で埋め込める
- ○ JSの設定変数で、表示するボタンなどを制御できる
- × カスタマイズ方法が独特。 文字サイズを任意指定できないので改造しようと思ったら、CSSの改造まで必要。
POSTでHTMLを飛ばそうとすると、下記のように少し工夫が必要になる。
詳細は上記URLの quill_test.js 参照。
var editor_input = document.getElementById(input_id); var editor_output = document.getElementById(output_id); var quill = new Quill(editor_input, baseOption); //inputにセットされている生HTMLを、変換してエディタに反映させる let initialContent = quill.clipboard.convert(editor_output.value); quill.setContents(initialContent); quill.root.innerHTML = editor_output.value; //エディタ入力時に、input に生HTMLをセットする quill.on('text-change', function(delta, oldDelta, source) { var editorHtml = editor_input.querySelector('.ql-editor').innerHTML; editor_output.value = editorHtml; });
Editor.js
- ○ 表が挿入できる
- × ブロックスタイル?と呼ばれる最新の見た目なので、使うのに慣れが必要かもしれない。通常のHTMLエディタを想定していると、現場の人に「なんじゃこれ」と言われるかも。
- × ツールバー?を固定できない
- × 行(ブロック)単位でしか、スタイル変更できない
感想
個人的なおすすめは quill。
が、ベストだとは思わない*1ので、ほかにいいのがあれば教えて。
バニラJavaScriptで頑張ってファイルアップロード処理を書く話
JSのライブラリを利用せずに、モダンなファイルアップロード処理を書こうとすると 割と色々コーディングしないといけないということが分かったのでメモ。
ネットに転がっているのは、
- D&DでUPする場合と、ファイルダイアログからUPする場合を共存させる考慮
- ファイルを追加でUPする場合の考慮
- 特定のファイルを削除する場合の考慮
- UPしたファイルを一覧で見たい場合の考慮
などが漏れているサンプルが多かったので、参考になれば幸い。
前提
- JQueryは使わない
- ライブラリは使わない(いわゆるバニラJS)Vueとか使ったほうが本当はきれいなんだけどね。
- IEなんて考慮しない
- 以下では、ある程度JavaScriptを分かっている人向けの適当な解説しかしない(メモなので)
サンプルページ
ファイルUPすると、リストでファイルが表示される。
https://gologius.github.io/test/file_upload/upload.html

ソース
下記参照。
gologius.github.io/test/file_upload at master · gologius/gologius.github.io · GitHub
ポイント1
input タグを二つ用意する。 片方がファイルを仮UPする用で、チェックが通ったものを、もう一方のinputにセットする。
HTML(抜粋
<form action="./upload.php" method="post" enctype="multipart/form-data"> <div id="dd_area" class="drop_area_off"> <div> ここにファイルをドラッグ&ドロップ or <input type="button" value="手動でファイル追加" onclick="clickUpload();" > </div> <input type="file" id="upload_files" name="upload_files[]"> <input type="file" id="tmp_files" name="tmp_files" multiple> </div> <div>アップロードしたファイル↓</div> <table class="file_list"> <tbody id="upload_files_list" > <!--実際の要素はJS側から挿入されるで--> </tbody> </table> </form>
Javascript(抜粋
function upload_files(new_files) { //変数準備 let sum_size = 0; let file_count = 0; let file_name_list = []; let work_transfer = new DataTransfer(); //通常の配列ではなく、datatransferでファイル管理する必要あり。 //現時点でUPされているファイルを走査する → 配列に格納 let now_files = document.getElementById("upload_files").files; for (var i = 0; i < now_files.length; i++) { var file = now_files[i]; work_transfer.items.add(file); sum_size += file.size; file_count += 1; file_name_list.push(file.name); } //アップロード対象のファイル群を走査 → 配列に格納 for (var i = 0; i < new_files.length; i++) { var file = new_files[i]; work_transfer.items.add(file); sum_size += file.size; file_count += 1; file_name_list.push(file.name); } //対象ファイルの走査が完了して用済みのため、tmp_filesはリセットする let elem = document.getElementById("tmp_files"); elem.files = new DataTransfer().files; //UPしてよいか判定 let errflg = false; if (sum_size > MAX_FILE_SIZE_MB * 1048576){ alert(`ファイルサイズの合計値は ${MAX_FILE_SIZE_MB}MB です`); errflg = true; } if (file_count > MAX_FILE_COUNT){ alert(`ファイルをUPできる最大個数は ${MAX_FILE_COUNT}個 です`); errflg = true; } //重複を削除したSetを生成。ファイル名が重複していると、Setの要素数がファイル数よりも減るので、それを利用する let uniqueSet = new Set(file_name_list); if (file_count != uniqueSet.size) { alert("同じファイル名が既に存在します"); errflg = true; } //UPしても問題ないと判断できれば、実際にファイルアップロードする if (errflg == false) { document.getElementById("upload_files").files = work_transfer.files; } //表示更新 update_file_list_html(); return; }
なんでこんなことをしているのかというと、 inputタグからファイルダイアログを開くと、そこにセットされていたファイルが上書きされてしまう。 上書きされてしまうので、追加でのファイルUPができないのである。
仮UPすることで、ファイル全数のサイズや個数のチェックもできるので、 仮UPしたほうがいろいろ都合もよい。
ポイント2
inputタグが持つfiles要素は、インデックスを指定して参照はできるが、 「直接の加工はできない」
できない例
let now_files = document.getElementById("upload_files").files; for (var i = 0; i < now_files.length; i++) { now_files[i] = tmp_file;// ←これはできない }
よって、datatransferを丸ごとfiles にセットしてあげる必要がある。
できる例
let now_files = document.getElementById("upload_files").files; let work_transfer = new DataTransfer(); for (var i = 0; i < now_files.length; i++) { work_transfer.items.add(tmp_file); } document.getElementById("upload_files").files = work_transfer;
特定のファイルを削除する場合には、「特定のファイルを除いた」datatransferをセットすれば、実現できる。
補足
もっとよい方法があれば教えて。