ラベル jQuery の投稿を表示しています。 すべての投稿を表示
ラベル jQuery の投稿を表示しています。 すべての投稿を表示

2024年3月10日日曜日

WEBアプリ[Enter]キーでフォーカス移動の問題点

HTMLの[Enter]でフォーカス移動

むかしはねぇ。業務系アプリのほとんどで、入力枠で[Enter]押されたら、次の入力枠にフォーカスを移すのって、当たり前でしたよね。
ところがどっこい。HTMLでの[Enter]は submit() がデフォルトになってる。
業務系WEBアプリとしては、[Enter]キーでフォーカス移動は、ユーザーからのご要望も強くありますね。
と、いうことで。
[Enter]キーでのsubmit()をフォーカス移動にしてたのが、次のコードです。

$(function(){
  $("input").on("keydown", function(e) {
    if ((e.which && e.which !== 13) && (e.keyCode && e.keyCode !== 13)) 
    {
      return true;
    }
    else
    {
      var count = $('input').length;
      var current_index = $('input').index(this);
      for(let index = current_index; index < count; index++)
      {
        var next_input = $('input')[index + 1];
        var is_hidden = $(next_input).is(':hidden');
        var is_readonly = $(next_input).prop('readonly');
        var is_button = $(next_input).is(':button');
        if(is_hidden || is_readonly || is_button)
        {
          continue;
        }
        $(next_input).focus();
        return false;
      }
      $('input')[current_index].blur(); 
      return false;
    }
  });
}(this));
textarea に移動しない!と思った人は変更してくださいw

MacOSの[かな]キーでフォーカス移動してしまう!

Mac 使いのお客様から、こんなクレームが来ました!
フォーカスが移動する、ってのなら上記コードが原因のわけです。
と、いうことで。
MacOS 機を入手して動きを調べてみました。

「かな」キーの keyCode が 13 !!!

なんでこんなことしてんですかねーw
数字(と記号の)郵便番号入力から、住所欄の入力に移動して「かな」キーを押すと、住所欄すっ飛ばして「名前」のところにジャンプしてしまうわけですw
『使えねぇ』と思われても仕方ありません。ええ。

keydown を keypress に

  $("input").on("keydown", function(e) {
この部分を

  $("input").on("keypress", function(e) {
に変更することで、対応できました。

まとめ

ちなみに、「かな」キーのkeydownでのkeyCode は 13 でしたが、 keypress での keyCode は 229 が入ってきます。

HTMLって日本語のことちっとも考えてくれてないよね。
IE にあった、IME の制御機能、入れてほしいよね・・・

とりあえず動いた。
めでたしめでたし。


参照
Enterキーを無効にする方法
日本語入力時のキーイベントの仕様変更と対策

2023年5月9日火曜日

チェックボックスがセットされていなくても POST パラメータに含める方法

Form の checkbox が not checked でも POST する

Formの内容をPOSTする際に、セットされていないcheckboxの値が渡されないと困ってしまうことが多いですよね?
ね?ね?w

以下 jQuery を使った(checked じゃないと POST できない)POSTの例

//フォーム入力情報取得
var form_data = new FormData($('#form-name').get(0));
//サーバに渡す。
$.post({
  type: 'POST', 
  url: url,
  data: form_data,
  }).done(function(response){
  }
  //以下略
});

これだとチェックボックスがチェックされている部分だけが渡されてしまいます。
 データベースの boolean 値を保存しようとしても、OFF の場合に値が渡されずに更新されなくなってしまいます。

そこで、こんな関数を作って対応しました。

/**
* フォームの入力情報を取得する。
* checkbox で OFF 状態の情報も含める
*/
GetFormData = function(form_tag)
{
    var tag_data = $(form_tag).get(0);
    var form_data = new FormData(tag_data);
    $(form_tag + ' input:checkbox').each(function(){
      var id = $(this).attr('id');
      var checked = $(this).prop('checked');
      if(!checked)
      {
        // OFF のチェックボックス状態も form_data に含める。
        form_data.append(id, checked);
      }
    });
    return form_data;
}

//フォーム入力情報取得
var form_data = GetFormData('#form-name');
//サーバに渡す。
$.post({
  type: 'POST', 
  url: url,
  data: form_data,
  }).done(function(response){
  }
  //以下略
});

まとめ

みごと、bool 値を更新することができるようになりました。
めでたしめでたし。

つか、なんで FormData は OFF の状態を取り込まない仕様にしてるんだろう・・・
困った仕様ですよね。

2021年12月6日月曜日

cakePHP3:javascript 3桁単位でカンマを表示する数字入力

cakePHP3.9 + bootstrap5 の環境で金額入力のために3桁単位で自動で数字を入力できるようにしようとしたんですね。

cleave.js ってのが便利そうだったので使ってみました。

参考
フォームのinput要素に電話番号・日付・時間・金額など、数字のフォーマットを定義できるスクリプト -Cleave.js
https://coliss.com/articles/build-websites/operation/javascript/format-input-text-content-cleave.html

cleave.js
https://github.com/nosir/cleave.js

上記のサイトなどを参考にして、次のようなコードを javascript に記述してました。
[project.js]

    var cleave = new Cleave('.input-decimal', {
      numeral: true,
      numeralThousandsGroupStyle: 'thousand'
    });

[project.css]

    .input-numeral {
        text-align: right;
    }

[slip.ctp]

    ≤div class="row">
        ≤h6 class="col-4 d-flex align-items-center">小計≤/h6>
        ≤div class="col-8">≤input type="text" class="form-control input-numeral input-decimal" value="10,000" />≤/div>
    ≤/div>
    ≤div class="row">
        ≤h6 class="col-4 d-flex align-items-center">消費税≤/h6>
        ≤div class="col-8">≤input type="text" class="form-control input-numeral input-decimal" value="1,000" />≤/div>
    ≤/div>
    ≤div class="row">
        ≤h6 class="col-4 d-flex align-items-center">合計≤/h6>
        ≤div class="col-8">≤input type="text" class="form-control input-numeral input-decimal" value="11,000" />≤/div>
    ≤/div>

困ったことに、数字入力のinputタグが複数あると、上手く動いてくれなかったんです。
chrome の開発者ツールでは、以下のようなメッセージが出てしまいました。

cleave.min.js:8 [cleave.js] Multiple input fields matched, cleave.js will only take the first one.

いやいや、伝票入力画面に数値入力が一か所しかないなんてありえないでしょ!
ということで調べた結果、javascript を次のように変更しました。

[project.js]

    $('.input-decimal').toArray().forEach(function(field){
      new Cleave(field, {
        numeral: true,
        numeralThousandsGroupStyle: 'thousand'
      });
    });

伝票用のフォーム画面では、金額入力フィールドを動的に追加できるようにしましたが、追加の都度 new Cleaveするようにして、ちゃんと動いてくれました。
めでたしめでたし。

2021年10月21日木曜日

Ajax post で WEB-API 呼び出そうとしたらパラメータが渡せなくて少し悩みました。

Javascriptのコード(抜粋)

	var params = [];
	params['date'] = '2021-10-21';
	var url = 'APIのURL';

	$.post({
	      type: 'POST', 
	      url: url,
	      dataType: 'json',
	      data: params,
	      cache: false,
	    }).done(function(response){
	        /*do someting*/
	    }).fail(function(XMLHttpRequest, textStatus, error){
	        /*do someting*/
	    }).always(function(data){
	        /*do someting*/
	    });

受け口となるAPIのコード(cakePHP3.x の controller)

    public function index() 
    {
        $date = $this->request->getData('date');
        ;//以下略

XAMPP+VS Code 環境でブレイクポイントを貼って $date 変数の中身を見ると
からっぽ!
なぜじゃぁぁぁぁ!。

ということで、小一時間悩みました。
わかる人にはすぐわかるのかもしれませんが、この何にも警告を出してくれないトラップは時間かかってしまうことがありますね~。


間違っているのは javascript 抜粋の1行目。

	var params = [];

ここです!

正しくは

	var params = {};

これだけ。 わすれないように、メモ。っと。

2021年1月11日月曜日

jquery VIDEOタグでsrcを変更すると再生できなかった。

 HTML の VIDEOタグを用意して、アクションで自動的にビデオを再生するようにしてみましたら、「再生できません」というエラーで困っちゃいました。

HTML(抜粋)

<div id="div_video">
  <video id="id_video" poster="poster.gif" autoplay loop muted></video>
</div>

javascript(抜粋)

<script type="text/javascript" src="/js/jquery.min.js"></script>
<script type="text/javascript">
function play_video() {

    $('#id_video').attr('src', "video.mp4");
    $('#id_video').get(0).play();
}
</script>

こんな感じです。window.onload() でやると再生できるんですが、アクション後に実行すると poster.gif は表示されますが、ビデオ再生はうまくいきませんでした。

開発者ツールで $('#id_video').attr('src') を見ると、予定されていない内容が入ってます。

video タグでは <source></source>タグを使って複数のファイルを指定できますので get(0) がおかしいのだと思われます。

今回の再生は複数ファイルは必要ないので、get(0) で正しく処理できるよう、次のように記述しました。

function play_video() {
    $('#div_video').children().remove();
    $('#div_video').append('<video id="id_video" autoplay loop muted></video>');
    var target = $('#id_video');
    target.attr("poster",  "poster.gif");
    target.attr("src", "video.mp4");
    target.get(0).play();
}

毎回 <video>タグを作り直すことで get(0) が正しく取得できるようになります。

※ここでは書きませんが、上記アクション実行の前に、前回再生中のタグがある場合は再生を止める必要があるみたいです。(リークしてしまうことがあるのかな?)

※<video> の属性に 'muted' を付けているのは、Chrome でデバッグするとエラーになっちゃうからです。




2019年10月8日火曜日

WEBサイトの国際化、多国語化を実現する slang.js

「IT後進国」とまで言われるようになった日本ですが、いろいろな原因や要素があるのだと思います。
エコノミストではありませんので具体的な指摘なんかできないんですが、いわゆる『ホームページ』というのに、その片鱗があるような気がします。

お仕事でお役所とか企業様とかの『ホームページ』を編集したりすることがあるのですが、多くの方が、必要な情報を『ホームページ』に掲載した時点で(広く)公開した気になっていらっしゃいます。
実際には、メンテナンスしたページを一般の方が目にすることになるのかどうかはわからないのに。

『ホームページ』の意義とか役割を考えると、むしろ、商品やサービス、技術を広く公開できてナンボという世界だと思うのです。

日本の人口から考えると、日本語のWEBサイトを見てくれるのは、ほとんどが日本人になりますね。
海外でどのような言語が使われているかを考えると、英語でのWEBサイト提供は、これから先必須になってくると思います。

もちろん、諸外国からのアクセスでも、google翻訳がとっても役に立つようになっているのは事実です。

翻訳エンジンの精度は以前に比べるとものすごく素晴らしくなっています。
日本語のWEBサイトを英語や中国語に翻訳するのも、google のAPIを使って、すこぶる簡単に実現できる時代になっていますね。

まーでも、コンテンツの内容がどのように変換されるのかを担保できないというスタンスでは、WEBサイトを google翻訳に頼ってしまうことには躊躇する担当者も多いのではないでしょうか?
どこぞの国で書かれたマニュアルなんかが笑いものにされていたのと同じような世界になるのは避けたいものです。

そこで、WEBサイトを他国語に翻訳できるような仕組みがないものかと探してみましたら、こんなのを見つけました。

http://www.openxrest.com/translatejs/
(日本語の解説サイト)
https://webkaru.net/jquery-plugin/translate/

WEBサイトの訪問者は、言語選択ボタンでお好みの言語に変えてもらう、というおなじみの形式です。
そこ、なんか違うなーと思うんです。

英語版のOSで英語版のブラウザを使ってサイトを訪問してくる方って、英語でページを見たいと思うと思います。
日本語なんか読めませんし、どうかすると文字化けしてるかもしれません。
そんなページの右上に「English」と書かれたボタンみたいなところを見つけてクリックしてくれると、そこで初めて自分にも読める文章が現れる、というスンポー。
あまり良いインターフェースとは思えないんですね。

ブラウザに使用言語の設定があって、javascriptで取得できるようになってますから、そいつを利用するようにすれば問題解決です。

それに、上記の translate.js を使う場合、同一コンテンツの中に複数の言語リソースを含めなきゃいけないのもメンテナンス性を損なってると思うんです。

WEBサイトを英語で記述しておいて、ブラウザで設定される言語が英語以外の場合、対象となる翻訳情報を読み込んで表示させる。
そんな仕組みがあってもいいんじゃないでしょうか。


ということで、javascriptを使って書いてみました。

slang.js

今、会社の膨大なページをコツコツと英語に対応しようとしてます・・・

2019年1月21日月曜日

Perl uri_unescape で文字化け

実は文字化けにはその後も苦しんでおりまして。
原因となる現象をようやく突き止めましたのでサンプルプログラムを公開しますね。

use Carp::Heavy;
use strict;
use URI::Escape;
use Encode;
use encoding 'utf-8';

my $a1 = '%E8%A9%A6%E9%A8%93';
my $b0 = '試験';
my $b1 = uri_escape_utf8($b0); #内容は '%E8%A9%A6%E9%A8%93'
print("$a1\n");
print("$b1\n");
print("1\n") if($a1 eq $b1);    #当然のごとく1が出力される

my $a2 = uri_unescape($a1);
my $b2 = uri_unescape($b1);
print("1\n") if($a2 eq $b2);    #なぜか 1 が表示されない
print("$b2\n"); #こちらは '試験'
print("$a2\n"); #文字化け
exit;


use encoding 'utf-8' を取ったり use utf8; にしたりすると他所に
大影響が出てしまうため変更できません。

これ。本当にハマりましたよ。
いったい何がどうなっているのかさっぱりわかりませんでした。

※実際には CGI 上のパラメータが文字化けしてました。

上記の謎の動作ですが
$a1= encode_utf8($a1);
を呼び出すことで期待通りの動きをすることがわかりました。

さて、本番環境に対応しようと・・・
my $cgi = new CGI();
my $a2 = $chi->param('a2');
文字化けです。
CGI の sub new で取得するuri_encode されたパラメータに対して事前に
encode_utf8を実行しなければならないのに、POSTリクエストだから標準
入力を変更する術が見つかりません。

じゃあ、ってことで呼び出し側を GET にしましたら、なんの変更も加えず
文字化けしなくなりましたよ。
Perlモジュールのバージョンの影響かと思い、さんざん調査すること3日
こういうのって、あっけなく解決するもんなんですねぇ
あー眠たい。

2018年7月30日月曜日

HTML 枠内にできるだけ大きめの表示。大きければ縮小して全体を表示

WEBページ表示で、「Excel のように縮小して全体を表示したい」という衝動には何度も駆られますね。
住所表示用の枠を用意していて、通常はうまいこと表示できるけど長い住所だとはみ出してしまう、とか。
あともう一つ。「枠内にできるだけ大きく表示させたい」というのもあります。
PDFの編集領域とか宛名ラベル用のアプリケーションなどにそういった枠があります。
今回はその両方、つまり
『文字列が短いときは枠内にできるだけ大きく表示』
『文字列が長いときは枠内に縮小して全体を表示』
という2つの要求を満たしたい、という仕様です。
まぁ印刷する必要のあるページなどには必須だと思います。

WEB上を探していくつかダウンロードしてみましたけど、思うように動いてくれなかったので自作しました。
突っ込みどころあると思いますが、とりあえず動いたので公開しときます。
(きっとたくさんの人がこういった情報を求めているだろうと想像したのでw)

住所表示用に用意した、span id="span_address" のタグに「秋田県北秋田郡上小阿仁村大字沖田面字小蒲野下タ川原」を放り込みたいときのサンプルコードを示します。
(※住所は長い住所で検索したら出てきたもの)

<html>
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script type="text/javascript">
    <!--
      // sample
      window.onload=function()
      {
        $('#span_address').text('秋田県北秋田郡上小阿仁村大字沖田面字小蒲野下タ川原');
        adjust_tagfont();
      }
      // 表示、再表示時に呼び出す
      function adjust_tagfont()
      {
        //はみ出しそうなタグの親idを列挙
        var tags = ['div_address'];
        tags.forEach(adjust_tag);
      }
      // タグの確認
      function adjust_tag(tag, index, array_name)
      {
        if(document.getElementById(tag) !== null)
        { 
            $('#' + tag).autoSizeByWidth();
        }
      }
      // width/height のクラス
      function ssize(_width, _height)
      {
        this.width = _width;
        this.height = _height;
      }
      // 文字列表示の幅と高さを計算する
      function string_size(str, font_size)
      {
        var chk_span = $("#for_check");
        chk_span.text(str);
        chk_span.css('fontSize', font_size + 'px');
        var width = chk_span.outerWidth();
        var height = chk_span.outerHeight();
        chk_span.empty();
        return new ssize(width, height);
      }
      // 
      jQuery.fn.extend(
      {
        autoSizeByWidth: function()
        {
          $this = $(this);    // 枠
          this.each(function()
          {
            $this = $(this);
            var p_width = $this.width()
            var p_height = $this.height();
            var str = $.trim($this.text()); //センタリングなどの処理をはずす
            var fontSize = parseInt($this.css('fontSize').replace('px', ''));
            var child_size = string_size(str);
            // できるだけ大きく
            while((child_size.width < p_width) && (child_size.height < p_height))
            {
              child_size = string_size(str, ++fontSize);
            }
            //はみ出しているとき
            while((p_width < child_size.width) || (p_height < child_size.height))
            {
              child_size = string_size(str, --fontSize);
            }
            $this.css('fontSize', fontSize + 'px');
          });
          return this;
        },
      });
    -->
  </script>
</head>

<body>
  <span id="for_check" style="visibility:hidden;position:absolute;white-space:nowrap;">
  </span>
  <table width="400" border="1">
    <tr>
      <td width="300" height="50">
        <div id="div_address">
            <span id="span_address">&nbsp;</span>
        </div>
      </td>
      <td width="100">
        &nbsp;
      </td>
    </tr>
</body>
</html>

table タグで物理的な大きさを指定してます。
任意のサイズにして確認してみてください。

いちおう解説しますと・・・
まず枠の大きさを取得します。
フォントサイズを拡張して枠からはみ出すところまで確認した後で枠の中に納まるようフォントサイズを縮小していきます。
これだけなんだけど、まわりっくどいっすねw

お役に立てれば幸いです。