sikaku

ナノで利用不可能な文字を閲覧者が書き込めるようにする方法

ナノ利用不可能文字変換ツールとほぼほぼ同じ処理をサイト内フォームに組み込む方法です。

9割9分問題ないはずですが、万が一当スクリプトの利用が原因でメッセージが壊滅的な改変をされた場合も当サイトは責任を負いかねます。 ご了承ください。

設置フォームに組み込む

ソースコード

JavaScript
  1. <script>
  2. document.addEventListener('DOMContentLoaded',()=>{
  3. let $forms = document.querySelectorAll('.guest-send-form form,form.guest-send-form');
  4. if( !$forms.length ) return;
  5. let nanoEsc = str => str.replace(nanoEsc.tgt,nanoEsc.fnc);
  6. nanoEsc.fnc = c => '&#X'+c.codePointAt(0).toString(16)+';';
  7. nanoEsc.tgt = (()=>{
  8. let SJIS = new TextDecoder('Shift_JIS');
  9. let decode = arr => SJIS.decode(new Uint8Array(arr));
  10. let range = [137,151,153,159,224,233];
  11. let frac = [[129,64,126,128,172,184,191,200,206,218,232,240,247],[132,159,190],[136,159,252],[152,64,114,159,252],[234,64,126,128,164]];
  12. if(decode([135,64])=='\u2460') frac.push([135,64,93,95,117,126,126,128,156]);
  13. let map = [];
  14. let rangePush = (t,s,e) =>{ while(s<=e) map.push(t,s++) };
  15. for(let i=0;i<range.length;i+=2) {
  16. for(let j=range[i];j<=range[i+1];j++){
  17. rangePush(j,64,126);
  18. rangePush(j,128,252);
  19. }
  20. }
  21. for(let d of frac) for(let i=1;i<d.length;i+=2) rangePush(d[0],d[i],d[i+1]);
  22. return RegExp('[^'+decode(map)+'\u0001-\u03e7\u{186a0}-\u{10ffff}○Α-ΡΣ-Ωα-ρσ-ωЁА-яёぁ-んァ-ヶ0-9A-Za-z。-゚]','gu');
  23. })();
  24. let alt = parseInt(localStorage.getItem('nanoEscAlt'))||0;
  25. $forms.forEach($form=>{
  26. let $chk = $form.nanoEsc;
  27. if( !$chk && alt<0 ) return;
  28. let $elms = Array.from($form.elements);
  29. let $inputs = [];
  30. let submit = () =>{
  31. if(!!$chk&&!$chk.checked) return;
  32. let flg = !!$chk||0<alt;
  33. $inputs.forEach($i=>{
  34. let v = $i.value;
  35. if(!nanoEsc.tgt.test(v)) return;
  36. v = nanoEsc(v);
  37. if(flg||confirm('表示できない可能性のある文字が含まれています。 エスケープし、下記文面に変更してよろしいでしょうか?\n(壊滅的な変更がされている場合、ご利用環境で処理が正常に行われていない可能性があります。拒否をご選択ください。)\n'+v)) $i.value = v;
  38. });
  39. };
  40. $elms.forEach($i=>{
  41. switch($i.tagName) {
  42. case 'INPUT':
  43. if($i.type=='submit') $i.addEventListener('click',submit);
  44. if($i.type!='text') return;
  45. case 'TEXTAREA':
  46. $inputs.push($i);
  47. };
  48. });
  49. if(!!$chk&&alt) $chk.checked = 0<alt?true:false;
  50. });
  51. });
  52. </script>
  • 利用したいフォームのあるページ内に、どこでもいいので一度記述
  • でナノで利用不可能な文字をエスケープする関数を定義しています。詳細
HTML(form部分)
  1. <div class="guest-send-form">
  2. ここに反映させたいフォームを記述してください。
  3. </div>
  • フォーム内に<input type="checkbox" name="nanoEsc" />がある場合、確認アラート無しでチェックボックスの状態依存で処理を行います。(チェック有りなら実行)

ブックマークレット化

ソースコード

javascript
  • javascript:(()=>{let reg=(()=>{let SJIS=new TextDecoder('Shift_JIS'),decode=arr=>SJIS.decode(new Uint8Array(arr)),map=[],rangePush=(t,s,e)=>{while(s<=e)map.push(t,s++)},range=[137,151,153,159,224,233],frac=[[129,64,126,128,172,184,191,200,206,218,232,240,247],[132,159,190],[136,159,252],[152,64,114,159,252],[234,64,126,128,164]];if(decode([135,64])=='\u2460')frac.push([135,64,93,95,117,126,126,128,156]);for(let i=0;i<range.length;i+=2){for(let j=range[i];j<=range[i+1];j++){rangePush(j,64,126);rangePush(j,128,252)}}for(let d of frac)for(let i=1;i<d.length;i+=2)rangePush(d[0],d[i],d[i+1]);return RegExp('[^'+decode(map)+'\u0001-\u03e7\u{186a0}-\u{10ffff}○Α-ΡΣ-Ωα-ρσ-ωЁА-яёぁ-んァ-ヶ0-9A-Za-z。-゚]','gu')})(),p=t=>RegExp('^/\w+'+t).test(location.pathname),s=p('/panel/')?'&sharp;':'#';document.querySelectorAll('textarea,input[type="text"]'+(p('/form/\d+/preview(?:/|$)')?',input[type="hidden"]':'')).forEach($i=>{$i.value=$i.value.replace(reg,c=>'&'+s+'X'+c.codePointAt(0).toString(16)+';')})})()
  • 実行時点でセレクタがtextarea,input[type="text"]に合致する全ての要素(入力欄)を対象に文字の置き換え処理をします。
  • 実行ページがフォームメール機能のプレビューページの場合、対象要素にinput[type="hidden"]追加します
  • 実行ページがログイン後の管理用ページの場合、数値文字参照記述を&&sharp;X文字番号;に変更します

ブックマークレットとは

ブックマークレット - wikipedia

詳細な使用方法は「使用ブラウザ名 ブックマークレット」あたりでググってください。 スマホからでも使えます。

自身に編集権限のないページでも任意のJavaScriptが実行できるので、他者の管理するナノサイトにメッセージを送る際や、自身の管理するサイトの編集ページ等でも使えます。

補足

フォームメール機能での使用時の注意点

やっていることが結局「利用不可能な文字を探査して&#X文字番号;(数値文字番号記述)に置き換える」でしかありません。 ここで問題になるのが数値文字参照記述に#を含まざるをえない点です。

フォームメール機能の複数行入力欄に#を入力した場合のバグがネックなのと、プレビュー画面を挟むと数値文字参照記述がまた文字として解釈されてしまいエスケープの意味がなくなります。

設置フォームに組み込みの場合

問題点双方とも上記記事のスクリプトと併用で解消できるようにしています。 活用してください。

ブックマークレットでの利用の場合
『#』入力時のバグ

正直「気をつけてください」しか言えません。

プレビューで数値文字参照記述が無意味になる

プレビューページでもブックマークレットを実行してください。

nanoEsc関数について

部分でナノで利用不可能な文字をエスケープする為の関数を定義しています。

配布そのままだと送信ボタンをクリックした際に特定の入力欄を対象に文字の置き換え処理をしますが、他で使いたい方は該当部分のみを持ち帰り好きに組んでください。

呼び出し
エスケープ

nanoEsc(string)

第一引数string部分にエスケープしたい文字列を持たせてください。

文字列内のナノで利用不可能な文字のみを数値文字参照記述に変換して返します。

数値文字参照変換

nanoEsc.fnc(string)

第一引数stringで持たされた文字列の、一文字目の数値文字参照記述を返します。

ナノで利用可能な文字を取得

nanoEsc.tgt

ナノで利用不可能な文字範囲(UTF-16文字番号が1000〜99999の文字から『純粋なShift_JIS(+NEC独自拡張)』を除いた文字)の文字1字にマッチする正規表現(regexp型,フラグはgu)です。

6600文字超とそれなりに長いので内容は省略。 需要があれば公開しますが気になる人はコンソールに上記表示させて確認してください。