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

2024年11月17日日曜日

スタイルシートに指定している色で表示されない

Color picker で異なる色が表示される

WEBページの設計では、色にこだわるケースが多いですね。
顧客から指定された色でデザインをしていたんですが、おかしな現象がでました。
スタイルシートに指定している色で、表示されないのです。

コードでは次のように指定しています。

--color-main-bg: rgb(3, 180, 198);
.top-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    max-width: 100%;
    padding: 1rem;
    margin: 0 auto;
    background-color: var(--color-main-bg);
}

Chrome color picker で別の色が表示される

Chrome で表示させて、開発者ツールを開くと、図のようにちゃんとコーディングした内容が反映されています。

ところが、Chromeの拡張機能の Color Picker で表示されている部分を調べると

おいおい、どーして色が違うんだよ・・・
おれさまのコードのどこに問題があるって言うんだよ~・・・
使ってる bootstrap とか normalize とか milligram なんかが悪さしてるのかな~・・・
と、必死にデバッグするも、問題点が見つからない・・・・

マルチディスプレイ

ディスプレイを2つ並べて開発してるんですが、表示してるページをもう一方のディスプレイにスライドすると・・・
あら不思議。ちゃんと指定された色で表示されちゃいます。

いったい、どういうことヨ?
どうやら、ディスプレイがおかしいのだということで、調べてみたよ。

画面の色調整

コントロールパネルに「色の管理」というのがありまして。
「詳細設定」-「ディスプレイの調整」というボタンがありました。
ぽちっ!

なんだかわからないけど、とりあえず、「次へ」ボタンで進めていきます

まとめ

するってえと、見た目も Color Picker でもちゃんと表示されるようになりましたよ!

いやあ、てっきり自分のプログラムが悪いんだろうと、とっても長い時間悩みましたよ
ほんと、こーゆーの勘弁してほしいですわ。
ま、なおってくれたので良しとしましょう。
めでたしめでたし。

c.f.
https://support.hp.com/jp-ja/document/c04249810

2024年11月10日日曜日

bootstrap(v5) でブレークポイントが正しく表示されない


スマホサイズで改行されてしまう!

bootstrapでデザイン中に、スマホサイズでrow の col が12以内なのに改行されてしまう問題に遭遇しました。


<div class="container-fluid">
    <div class="row">
        <div class="col-6 col-sm-4 col-lg-2">
          ll
        </div>
        <div class="d-none d-sm-block col-sm-4 col-lg-4">
          lr
        </div>
        <div class="d-none d-lg-block col-lg-4">
          rl
        </div>
        <div class="col-6 col-sm-4 col-lg-2">
          rr
        </div>
    </div>
</div>

これ実行すると、スマホサイズの時、ll と rr 部分が改行されて出力されてしまいます。
なぜじゃあ?

解決方法

row の部分を次のように変更することで、無事行内に収まるようになりました。


<div class="container-fluid">
    <div class="d-inline-flex w-100 justify-content-between">
        <div class="col-6 col-sm-4 col-lg-2">
          ll
        </div>
        <div class="d-none d-sm-block col-sm-4 col-lg-4">
          lr
        </div>
        <div class="d-none d-lg-block col-lg-4">
          rl
        </div>
        <div class="col-6 col-sm-4 col-lg-2">
          rr
        </div>
    </div>
</div>

まとめ

けっこう格闘してしまった
動いたから、よし!
めでたしめでたし。

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年7月26日水曜日

WEBサーバで、一定時間だけ有効な認証キーで登録する

メールアドレスの入力確認のための方法

2度入力させるUIって、ほんとダメですよね。

メールアドレスを入力してください。(*)
確認のため、再度メールアドレスを入力してください。(*)
(*)必須項目。しかもコピペできないw

んでも、入力ミスっていたら、その後メール来ないし。(笑)
これ、よく見かけますよねぇ。
昔はうちもやってましたが(笑)

認証キーを送信して、入力させる方法

そこで、30分とか1時間だけ有効な認証キーを送って、それを入力してもらうようにするといいんですね。
これも、よく見かけるようになりましたが(笑)

こんな画面です。

メールアドレスを入力して「認証キー送信」ボタンを押してもらう。
受信したメールに記載の認証キーを入力して、本来の登録処理にする。
こうすることで、メールが届かなかったら、入力ミスだとわかるし、メールが届けば間違いないメールアドレスだと判断できますね
認証キーは一定時間(たとえば30分)だけ有効で、それを過ぎると無効になります。

で、これをどのようにサーバー側で実装しようか、ということですよ。

HTMLページ上の Ajax を使った Javascript は以下のような感じになります。

// 認証キーを送信する処理
onButtonSendAuthKey = function()
{
    // メールアドレスに認証コードを発行するサーバープログラム
    var url = '/regist-temporary';
    var params = {
        mail: $('#input-mail').val()
    };
    $.post({
        url: url,
        data: params,
    }).then(function(response){
        // 略
    });
}

// 入力されたメールアドレスと認証キーで登録する処理
onButtonEntry = function()
{
    // メールアドレスを登録するサーバープログラム
    var url = '/regist-user';
    var params = {
        mail: $('#input-mail').val(),
        auth_key: $('#input-auth_key').val()
    };
    $.post({
        url: url,
        data: params,
    }).then(function(response){
        // 略
    });
}

30分有効な認証キーをどう管理する?

ランダムな認証キーは乱数で構成すれば簡単にできますが、作成した認証キーをどのように管理するのか?
というのが今回のテーマです。
Session と Cookie を使って、ブラウザ側に記憶させる、という方法もあるでしょうけど、クライアント側に覚えさせるのは、ちょっと抵抗を感じてしまいます。
んでは、サーバー側で対応するとすると、どうすべきでしょう?
データベースに一時ユーザーテーブルを用意しておく、という方法が一般的のようです。

一定時間を経過したら、その情報を削除しなければならないわけで、それには cron でシェル作ってDBの作成時間を見て delete、と。
と考えるとですね、おっさんプログラマにはリソースの膨大な無駄遣いのように思えて仕方がないのですよ(笑)

サーバー側の認証キー送信処理(/regist-temporary)では以下の手続きが必要になります。
・認証キーを生成する。
・メールアドレスに認証キーを送信する。
・メールアドレスに対して発行した認証キーを記録する。
・30分経っても登録されない場合、認証キーを削除する。
サーバー側の登録処理(/regist-user)は以下の手続きが必要です。
・認証キーが無効になっていないかを判断する。
・メールアドレスと認証キーが一致するか判断する。
・本来の登録処理を行う。
という流れなんですが、リソースの使用を最小限に留めて、サクサク動くようにできないもんでしょうかね。

/dev/shm を使う!

そこで、思いついたのが、一般的な Linuxサーバに必ず用意されていて、あまり利用されている風ではない、/dev/shm (RAMディスク)を利用する方法です。
1.ユーザーごとに生成した認証キーを /dev/shm/サービス名/temp_auth/ ディレクトリに記録しておく。
2.登録時には、記録内容を照合する。
3.cron で記録ディレクトリの一定時間経過したファイルを削除する。
という方法ですね。

メールアドレスごとに認証キーを生成して、RAMディスクに記録する

// メールアドレスごとの認証キーを生成して、送信する処理
function send_auth_key($mail)
{
    // ランダムな認証キーを生成
    $auth_key = $this->create_auth_key();
    $path = '/dev/shm/service/temp_auth';
    $rc = mkdir($path, 0777, true);
    if(!$rc)
    {
        //エラー処理
    }
    //メールアドレスを Base64(URL)エンコード
    $mail_hash = $this->Base64UrlEncode($mail);
    // 拡張子に .key を追加(なんとなくw)
    $fname =  $mail_hash . '.key';
    $filename = "$path/$fname";
    $rc = (0 < file_put_contents($filename, $auth_key));
    if($rc)
    {
        $rc = chmod($filename, 0666);
        if($rc)
        {
            // 認証キーをメールで送信(省略)
            $rc = $this->send_auth_key($mail, $auth_key);
        }
    }
}

// ランダムな認証キー生成
function create_auth_key($column = 6)
{
    $authKey = '';
    $digits = '0123456789';

    for ($i = 0; $i < $column; $i++) {
        $authKey .= $digits[rand(0, strlen($digits) - 1)];
    }

    return $authKey;
}

// Base64URL encoder
function Base64UrlEncode($data) { 
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); 
} 
  
// Base64URL decoder
function Base64UrlDecode($data) { 
    // = 埋めしなくてもいける
    return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); 
} 

メールアドレスを BASE64エンコードするのは、メールアドレスの中にファイル名に使用できない文字が含まれるかもしれないのを避けるためですね。
BASE64で利用される +と/ の記号は -と_ に変換することで、ファイル名として機能するようにしています。
あと、chmod 0666 しておくのは、apache と cron でアクセスしてくるユーザーが異なるためです。

一時ファイルを一定時間後に削除する、のはcron で以下のように設定しました。(例は3分ごとに実行してるので、少しタイムラグあります)

#crontab で認証キーの制限時間超えたファイルを消す
*/3 * * * * find /dev/shm/service/temp_auth/ -name '*.key' -mmin +30 -delete > /dev/null 2>&1

実際に認証キーとメールアドレスが送られてきたときの処理コードを入れておきます。

function checkAuthKey($mail, $auth_key)
{
    $rc = false;
    $error_message = '認証キーが異なっているか、または期限が切れています';
    $path = '/dev/shm/service/temp_auth';
    $mail_hash = $this->Base64UrlEncode($mail);
    $fname =  $mail_hash . '.key';
    $filename = "$path/$fname";
    $saved_key = false;
    if(file_exists($filename))
    {
        $saved_key = file_get_contents($filename);
    }
    if($saved_key)
    {
        $rc = (strcmp($auth_key, $saved_key) == 0);
    }
    return [$rc, $filename, $mail_hash, $error_message];
}

まとめ

今回はサーバー側で一時的な認証キーを生成してメールアドレスの確認と登録処理に至るプロセスで、Cookieやデータベースを使わない方法をまとめてみました
こういった需要って、よくあることだと思うので、参考にしてくださいまし。
実際、サクサク動いてくれるし間違いも起こりにくいので、安全に運用できています。
めでたしめでたし。

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 + bootstrap5 プロジェクトで郵便番号入力から自動的に住所欄を入力できるようにしてみました。

ふだん、css/jsはバージョンによって動きが変わったりしないよう、サーバ上にコピーして利用するようにしてますが 市区町村合併などで郵便番号が変化する場合があるので、こちらはgithubのサイトを参照するようにしてます。

[slip.ctp]

≤?php

$this->Html->script("//yubinbango.github.io/yubinbango/yubinbango.js", ['block' => true]);

?>

≤div class="col-md-6 h-adr">
    ≤span class="p-country-name" style="display:none;">Japan≤/span>
    ≤table class="table_client_info as_bd_cl">
        ≤tr>
            ≤th>≤input type="button" class="form-control as_button" value="着住所">≤/th>
            ≤th style="text-align: right;">郵便番号≤/th>
            ≤td>
                ≤input type="text" class="form-control p-postal-code" placeholder="郵便番号を入力" />
            ≤/td>
        ≤/tr>
        ≤tr>
            ≤th>住所1≤/th>
            ≤td colspan="2">
                ≤input type="text" class="form-control p-region p-locality p-street-address" placeholder="住所を入力" />
            ≤/td>
        ≤/tr>
        ≤tr>
            ≤th>住所2≤/th>
            ≤td colspan="2">
                ≤input type="text" class="form-control p-extended-address" placeholder="建物名、部屋番号を入力" />
            ≤/td>
        ≤/tr>

cssクラス部分は、サイズとか罫線を設定してます。
いやー。しかし、こりゃ便利だw
めでたしめでたし。

【追記】
最近になって、郵便番号での住所入力が必要になって、自分のブログを参照にしてみたら、なかなか動いてくれなかった(笑)
原因は、class="h-adr" を付加してなかったからでした。
上記の例では上部の div タグに設定してますね。
ここ、忘れないようにしてくださいw

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年11月8日月曜日

A4横 CSS(スタイルシート) の landscape がうまく行かない

「A4横」左図の帳票レイアウトを作成して印刷しようとしたら、横幅が狭く表示されてうまく行きませんでした。

WEBサイトを検索すると、あちこちにこうすればできると書いてある。

ちなみに、bootstrap5 を使ってレイアウトしてます(帳票なのでレスポンシブは考慮してない)

@page {
    size: A4 landscape; 
    size: 297mm 210mm;
    margin: 0mm;
}

A4横に、なるにはなるんだけど、コンテンツの横幅がどう見ても狭い。
A4縦の時の横幅を超えない(程度の)横幅でしか印刷されない・・・・
なぜじゃ!?

いろいろ調べたり、調べてもらったりして bootstrap がまずいことがわかりました。
(Hさん、ご協力、ありがと。)

bootstrap の次の部分が影響してましたよ、と。

.container, .container-lg, .container-md, .container-sm{
 max-width: 960px;
}

以下のようにスタイルシートを追記すると、ちゃんとA4横で印刷されるようになりました。

@media print {
    .container {
         max-width: 297mm !important;
    }
}


めでたし、めでたし。

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 でデバッグするとエラーになっちゃうからです。




2018年12月30日日曜日

perl CGI HTML::Template で文字化け

Perl CGI での文字化け問題は何年も前に解決させたはずだったのですが(以前は Perl + Template の場合)
新しい CentOS (サーバに無料で入ってる Ver 6)の環境で、現在動作しているcgiを実行すると文字化けしてしまう現象に悩まされました。

ハマった手順を書いてみますね。

1)httpd.conf の変更
文字化けはこれでなおる!とネット上のあちこちに書いてあります。
# vi /etc/httpd/conf/httpd.conf

AddDefaultCharset off
または
#AddDefaultCharset off コメントアウト。


動作結果:NG
世界中でほとんど解決しているらしいのですが、うまくいきません。

2)php.ini の変更
# vi /etc/php.ini

;default_charset = "UTF-8"

default_charset = ""
に変更


動作結果:NG
そもそも php 使ってませんし。

ここでブラウザ側のレスポンスヘッダを確認してみますと utf-8 となっていました。
んー?なのに文字化け?理解できないぞ・・・

ちなみに、cgi のソースや HTML, CSS, JS, テンプレートファイルなど、すべてのファイルは UTF-8 で記述してます。(改行は LF)
なぜだろう、と、試験を実施することに。


3)簡単なHTMLを用意
[test.html]

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>テストページ</title>
    </head>
    <body>
        UTF-8で記述されたページ
    </body>
</html>


動作結果:なんと、うまく表示されます。

4)cgi だとダメなのかな?
[test.cgi]

#!/usr/bin/perl --
print "Content-Type: text/html; charset=utf-8\n\n";
print "<html><body><div>\n";
print 'クオート文字';
print '<br>';
print "ダブルクオート文字";
print '<br>';
print "<div></body></html>\n";
exit;

クオートとダブルクオートで分けたのは、 perl の動作で文字化けしているのかどうかを確認するためです。

動作結果:なんと、うまく表示されます。

5)HTML::Template が怪しい。
どうやら使用している HTML::Template が怪しいのではないかとあたりを付けて検索したら情報がありました。
HTML::Template 2.98 で UTF問題が解決してる!というのです。
移行先のサーバーの HTML::Template は Ver,2.97 です。
ちなみにうまくいっていた旧サーバーの HTML::Template は Ver,2.94 でした。

Ver 2.98 のソースはここにありました。
https://github.com/mpeters/html-template

CPAN からのインストールしかやったことないので、git からどうやってインストールするのかわからずw
ダウンロードした HTML/Template.pm, HTML/Template/FAQ.pm をそのまま perl5 のファイルに上書きw

文字化けする cgi を動作させてみました。

動作結果:NG
ここまで、大量に時間を食ったにもかかわらず、うまくいかないとは・・・

6)binmode => 'utf8' を記述
既存 cgi の new HTML::Template 構文で、binmode => 'utf8' を追加する、との記述があったので
試してみました。

動作結果:NG
この記述は、上記リンクをたどる際に対応したパッチを当てたソースの場合に有効だったもので、動かないことは予想できていました。

7)utf8 => 1 を記述
HTML/Template のドキュメントを読み、new 構文の utf8 オプションがあることを発見。(旧サーバにはないオプションでした。)

既存 cgi の new HTML::Template 構文で、utf8 => 1 オプションを追加して実行してみました。

my $tmpl = HTML::Template->new(die_on_bad_params => 0, filename => $file, utf8 => 1);

動作結果:おお!!!!ようやく文字化けせずに表示されました!

しかしながら、問題があります。
既存プログラムの cgi ファイルは山のようにあります。
その全部にフラグを追加するのは困難ですよ。
デグレードなんか発生させちゃった日にゃ目も当てられません。
なんとかならないかな・・・

8)HTML::Template を編集。
perl5 の HTML/Template.pm を開いてみると、次のような部分なありました。

my %OPTIONS;
BEGIN {
    %OPTIONS = (
        debug                       => 0,
        ;
        utf8                        => 0,
        ;

ええい、こいつを1にしてしまえ!

        utf8                        => 1,

と変更した後で、既存の cgi に戻して動作

動作結果:OK

文字化けが解消されました!!!

モジュールの挙動が変わるなんて、ほんと困りものです。

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

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



2017年6月16日金曜日

HTMLで炎に燃える文字

野球中継を見ていたら、バックスクリーンに炎に燃える文字が出てまして。

文字が燃えてるんじゃなくて、文字のフォント部分の背景が燃えてるんですね。

で、こいつをHTMLでできるんじゃないかとやってみたよ。


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
<!--
.fireback
{
text-align: center;
line-height: 1.1;
font-size: 5em;
font-weight: bold;
display: inline-block;
margin: .45em;
padding: .5em .75em;
color: #fff;
background-color: #000;
background-image: url(./fire.gif);
background-repeat: no-repeat;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
-->
</style>
</head>
<body>
<div class="fireback">
熱男<br>
</div>
</body>
</html>

ここから実際の表示を見ることができます。