アナログCPU:5108843109

ゲームと音楽とプログラミング(酒と女とロックンロールのノリで)

('ω') < イザユケエンジニャー

jQueryでclassをもちゃもちゃする

基本編(add, remove, toggle, has)

追加
$(要素).addClass(class名);
削除
$(要素).removeClass(class名);
あれば削除、なければ追加
$(要素).toggleClass(class名);
あるかどうかを確認
// あればtrue、なければfalse
$(要素).hasClass(class名);
実装サンプル







<style>
#testdiv {
    padding: 5px;
}
.back-red{
    background: #F00;
}
</style>
<div id="testdiv" class="">
  <input type="button" onclick="addBackRed();" value="背景を赤くする(add)">
  <input type="button" onclick="removeBackRed();" value="背景を赤くするのをやめる(remove)">
  <input type="button" onclick="toggleBackRed();" value="背景の色を切り替える(toggle)">
  <input type="button" onclick="hasBackRed();" value="背景の色が赤いかどうか確認する(has)">
</div>
<script>
function addBackRed(){
    $("#testdiv").addClass("back-red");
}
function removeBackRed(){
    $("#testdiv").removeClass("back-red");
}
function toggleBackRed(){
    $("#testdiv").toggleClass("back-red");
}
function hasBackRed(){
    if ($("#testdiv").hasClass("back-red")){
        alert("赤いです");
    }
    else{
        alert("赤くないです");
    }
}
</script>

応用編?

基本的に、addとremoveとtoggleとhasさえあればなんとかなりそうなので、あとはその組み合わせ。
というか厄介なのはhas。

「複数のclassをすべて持っているかどうか確認したい」
「複数のclassのどれかを持っているかどうか確認したい」
「複数のclassがすべて一致する(過不足がない)かどうか確認したい」
という時のための関数を作ったので置いとく。

複数のclassをすべて持っているかどうか確認したい
function hasAllClass(obj, c){
    var c_list = c.split(" ");
    var retflg = true;
    $(c_list).each(function(i, e){
        if (!obj.hasClass(e)){
            retflg = false;
        }
    });
    return retflg;
}

使用例

<span id="testspan" class="a b c">にゃーん</span>
<script>
  console.log( hasAllClass($("#testspan"), "a b c") ); // true(完全に一致してるのでOK)
  console.log( hasAllClass($("#testspan"), "b c a") ); // true(順番が変わってもOK)
  console.log( hasAllClass($("#testspan"), "a b"  ) ); // true(足りないのはOK)
  console.log( hasAllClass($("#testspan"), "a b d") ); // false(余分なのはNG)
</script>
複数のclassのどれかを持っているかどうか確認したい
function hasEitherClass(obj, c){
    var c_list = c.split(" ");
    var retflg = false;
    $(c_list).each(function(i, e){
        if (obj.hasClass(e)){
            retflg = true;
            return false;
        }
    });
    return retflg;
}

使用例

<span id="testspan" class="a b c">にゃーん</span>
<script>
  console.log( hasEitherClass($("#testspan"), "a b c") ); // true(完全に一致してるのでOK)
  console.log( hasEitherClass($("#testspan"), "b a"  ) ); // true(順番違いや足りないのはOK)
  console.log( hasEitherClass($("#testspan"), "a d"  ) ); // true(存在しないものが混じっててもOK)
  console.log( hasEitherClass($("#testspan"), "d e"  ) ); // false(存在しないものしかないのはNG)
</script>
複数のclassがすべて一致する(過不足がない)かどうか確認したい
function hasOnlyClass(obj, c){
    var cmp_c_list = c.split(" ").sort();
    var tag_c_list = obj.attr("class").split(" ").sort();
    return cmp_c_list.toString() == tag_c_list.toString();
}

使用例

<span id="testspan" class="a b c">にゃーん</span>
<script>
  console.log( hasOnlyClass($("#testspan"), "a b c")   ); // true(完全に一致してるのでOK)
  console.log( hasOnlyClass($("#testspan"), "b a c")   ); // true(順番が変わってもOK!)
  console.log( hasOnlyClass($("#testspan"), "a b"  )   ); // false(足りないのでNG)
  console.log( hasOnlyClass($("#testspan"), "a b c d") ); // false(余分なのでNG)
</script>

FireFoxでJSをワンクリックで動かせるようにする

ブックマークのURL部分にJSを仕込むだけなので、
「普通のブックマークをアドレスバー付近からワンクリックでアクセスできるようにする」でもある。
もっと言えば「ブックマークツールバーを使う」でしかない。

手順1.目的のJSをブックマークに登録する

Ctrl+Bとかでブックマークを開き、
「ブックマークツールバー」を右クリックで「新しいブックマーク」します。
適当な名前を付けて、URLのところにJSを仕込みます。
保存すると、まずは普通のブックマークになりました。

ブックマークを既に作ってある場合は
「ブックマークツールバー」へドラッグ&ドロップしてください。

手順2.ブックマークツールバーの中身を表示する

アドレスバーの「カスタマイズ」で、
「ブックマークツールバーの項目」を好きなところに設置します。

以上!

f:id:honey8823:20180907164512p:plain
こんな感じになります。

ちなみに

今回はこれを仕込むために設置しました。
君はHTML5の contentEditable 属性を知っているか | Tips Note by TAM

javascript:(function(b){b.contentEditable=!b.isContentEditable;})(document.body);

これで画面仕様書を作るのが楽になったぞ。

ドラッグ&ドロップで列を入れ替えられるようにする

WEBアプリで、
「テーブルの列をドラッグ&ドロップで並べ替えられるようにしたい!あと、並べ替えた結果はユーザごとに保存しておけるようにしてほしい!」とか言われて「は?」と思ったんですが
調べてみるとJSライブラリがあったのでそれでさくっと実装。

ここからダウンロードできますし、動くサンプルもあります。
danvk.org » dragtable: Visually reorder all your table columns

実装方法はというと、
ダウンロードしたら適当なところに設置して、

<script src=" ... /dragtable.js"></script>

と読み込んで、テーブルタグにclassを設定するだけ。

<table class="draggable">

以上。

…あっ、結果は保存できるようにするんだった、と思ったのですが
なんとcookieへの保存機能もデフォルトで付いてる。すごい。

tableタグのidを利用して保存し分けているようなので、
同じサイト内で複数テーブルにこれを利用するときは注意、くらいでしょうか。
(別のページであってもidを分けるよう注意するだけ)

あと、サイドバーやヘッダなどを付けている場合、
付け方によってはドラッグ中の表示がその幅だけズレます。
もしそうなったときはコードをちょっと修正します。

(わたしがダウンロードしたときは)239行目くらい:

// 元の記述
//new_elt.style.left = obj_pos.x + "px";
// 修正した記述(左に250pxサイドバーがあって右にずれていたので、x座標から250引いている)
new_elt.style.left = (obj_pos.x - 250) + "px";

参考
ドラッグ&ドロップでテーブルの列を入れ替える - JavaScript dragtable | ホームページ制作のサカエン(墨田区)

ポップアップアラートのかんたん実装

「単純なアラート」「OK/NGのみの二択アラート」「ページ離脱時の警告」の三本立て。
ブラウザ依存なのでデザインもクソもない代わりにめちゃくちゃ簡単実装。

アラートを表示

ただメッセージを出すだけのやつ。

alert("エラーメッセージ");

サンプル:これを押すと出ます。

二択で答えさせる

「ログアウトしますか?」とか「削除してよろしいですか?」みたいなやつですね。

if (confirm("質問:どちらか押してください")){
    alert("OKでした");
}
else{
    alert("NGでした");
}

サンプル:これを押すと出ます。

ページ離脱時に警告を出す

あのウザいやつ。意外と実装は簡単でした。
ただ、↓のように指定したメッセージってあんまり表示されないような…。
FirefoxChromeではブラウザ固有のメッセージだったので、似たような意味合いのものを一応入れておくか…くらいでよいかも。

window.addEventListener("beforeunload", function(e){
    e.returnValue = "ページを閉じていいですか?";
}, false);

サンプルとしてこのページに仕込んであります…が、それだとウザいので、
↓のボタンを押してから離脱しようとすると警告が出るようにしてあります。
※ブラウザによっては動作しないかも?

また、フォーム送信時など、必要ないときにも出てしまったりするので、
そういうときはイベントを解除してやる必要があります。

// イベントの内容を変数に入れておく
var stopExitEvent = function(e){
    e.returnValue = "ページを閉じていいですか?";
}
// イベント設定
window.addEventListener("beforeunload", stopExitEvent, false);

// 解除したい場面で呼んでやる
function releaseStopExitEvent(){
    window.removeEventListener("beforeunload", stopExitEvent, false);
}

さっきのボタンを押しちゃった場合でも、こっちを押してから遷移すると警告は出ません。

jQueryならこんな感じ。

var stopExitEvent = function(e){
    return "ページを閉じていいですか?";
}
$(window).on("beforeunload", stopExitEvent);
function releaseStopExitEvent(){
    $(window).off("beforeunload", stopExitEvent);
}

PHPでファイルを扱うときのいろいろ

ファイルの書き込み読み込みやらCSVやテキストがどうやらというのは長くなるので、
ファイル自体の存在とかコピーや削除とかそういうやつ。

ファイルやディレクトリの存在を確認する

<?php
if (!file_exists(パス))
{
    // ファイルが存在しない
}

PHP: file_exists - Manual

パスで示された何かがファイルであるかどうかを確認する

<?php
if (!is_file(パス))
{
    // ファイルじゃない何か
}

PHP: is_file - Manual

パスで示された何かがディレクトリであるかどうかを確認する

<?php
if (!is_dir(パス))
{
    // ディレクトリじゃない何か
}

PHP: is_dir - Manual

ディレクトリを作る

<?php
mkdir(パス);

ちなみに空のファイルを作る場合はtouchで。
PHP: mkdir - Manual
PHP: touch - Manual

ファイルを移動する/リネームする

<?php
rename(元のパス, 新しいパス);

PHP: rename - Manual

ファイルを削除する・ディレクトリを削除する

ファイル削除

<?php
unlink(パス);

ディレクトリ削除

<?php
rmdir(パス);

PHP: unlink - Manual
PHP: rmdir - Manual

パーミッションの変更

<?php
chmod(パス, 0755);   // モード変更
chown(パス, "root"); // 所有者変更

PHP: chmod - Manual
PHP: chown - Manual

グループも変えられるけど使わないな。
PHP: chgrp - Manual

PHPでファイルパスを扱うときのいろいろ

主にファイルパスの文字列をもにょもにょわちゃわちゃしたりするときに使うやつ。

きれいなパスをつくってくれるやつ

<?php
$path = "./../hoge/";
echo( realpath($path) );

例えば
/var/hoge/ というディレクトリが存在する状態で
/var/www/ から上記コードを実行すると、
いろいろ解決して「 /var/hoge 」を返してくれます。
最後のスラッシュは付かないことに注意。
指定パスがそもそも存在しないときはfalseを返してくれます。

PHP: realpath - Manual

ファイルパスをディレクトリやファイル名や拡張子に分割してくれるやつ

<?php
$path = "/var/www/hoge.php";
var_dump( pathinfo($path) );

これを実行すると以下のような表示になります。
ディレクトリパス・ファイル名・拡張子・拡張子なしファイル名がわかります。
どうやら文字列を解析しているだけのようで、ファイルが存在しなくてもやってくれます。

array(4) {
  ["dirname"]=>
  string(8) "/var/www"
  ["basename"]=>
  string(8) "hoge.php"
  ["extension"]=>
  string(3) "php"
  ["filename"]=>
  string(4) "hoge"
}

ドットから始まるファイル名など、特殊なパターンでは意図通りの動きにならないかもしれません。
PHP: pathinfo - Manual

第二引数に以下パラメータのいずれかを渡すことで、特定の要素のみを受け取ることもできます。

  • PATHINFO_DIRNAME
  • PATHINFO_BASENAME
  • PATHINFO_EXTENSION
  • PATHINFO_FILENAME

これひとつを覚えておけばとりあえずOKそうですが、
以下のように「dirname」「basename」関数を使うこともできます。

<?php
$tmppath = "/var/www/hoge.php";
echo( dirname($tmppath) );              // /var/www
echo( basename($tmppath) );             // hoge.php
var_dump( basename($tmppath, ".php") ); // hoge

PHP: dirname - Manual
PHP: basename - Manual

CSSの指定方法いろいろメモ

バック兼業フロントエンドエンジニア1年生、昔はHTMLは書いてたけどCSSすごい苦手だったのが今更響いている…。

サンプルを作って試したのをメモ。

<HTML>

<div id="divid1" class="divclass1 divclass2">
  <span>test1</span>
  <div id="divid2" class="divclass1 divclass3">
    <span>test2</span>
    <div id="divid3" class="divclass2 divclass3">
      <span>test3</span>
      <input type="checkbox" class="cbclass1" checked>
      <input type="checkbox" checked>
    </div>
  </div>
</div>

CSS

/* すべてのdiv要素に有効 */
div {
    margin: 5px;
}
/* idが「divid1」「divid2」「divid3」のいずれかの要素であれば有効 */
#divid1, #divid2, #divid3 {
    padding: 5px;
}
/* idが「divid1」の要素に有効 */
#divid1 {
    background: #CCC;
}
/* 「divclass1」のclassを持つ要素に有効 */
.divclass1{
    border: #000 solid 1px;
}
/* idが「divid1」の要素の直下にあり「divclass3」classを持つ要素に有効 */
/* (=直下でなく孫以下の要素の場合は無効) */
#divid1 > .divclass3{
    border: #F00 solid 1px;
}
/* idが「divid2」の要素以下にあるすべてのspan要素に有効 */
#divid2 span{
    background: #FF9;
}
/* 「divclass2」「divclass3」の両方のclassを持つ要素に有効 */
.divclass2.divclass3{
    border: #0F0 solid 2px;
}
/* 「divclass2」「divclass3」の両方のclassを持つ要素以下にあるすべてのspan要素に有効 */
.divclass2.divclass3 > span{
    font-weight: bold;
}
/* 「cbclass1」を持つ要素にchecked属性がある場合に有効 */
.cbclass1:checked{
    cursor: pointer;
}
/* typeがcheckboxであるinput要素のうち、「cbclass1」を持たず、チェックされていない場合に有効 */
input[type=checkbox]:not(.cbclass1):not(:checked){
    outline: solid 3px #F00;
}

ざっくりまとめ

  • 要素の特定方法
    • 「div」ならdivタグ
    • 「#div」ならdivというid
    • 「.div」ならdivというclass
  • 複数要素を並べるとどうなるか
    • カンマ区切りで列挙された要素すべて
    • 「 > 」で直下指定
    • スペースを空けて書けば以下要素すべてからの指定
    • スペースを空けずに書けば両方を持つ要素を指定
    • 「[type=checkbox]」「:checked」など属性指定できる
    • 「:not()」で否定

↓実装サンプルここから
================================


test1

test2

test3



================================
↑実装サンプルここまで

なんか、はてブロの元のCSSが混じってて思ったのと違うけど
自分で書いたCSSは適用されてるからいいか。

フォルダツリー型のAndroid音楽アプリ「LISNA」が最高だった

play.google.com


久しぶりに「お布施させてほしい」系アプリを見つけた感。
(というかこれ系のアプリは過去にもいろいろ探してたのになんで見つからなかったんだろう…不思議…)

フォルダツリー型であるだけで大正義なのに、欲しい機能がほぼ過不足なくきっちり揃ってて最高。

良かったところ(良かった順)

  • フォルダツリー最高
    • 好きな階層内に絞った順次再生やランダム再生ができる
      • 例えばゲームサントラだと「ゲーム曲フォルダ>シリーズ名フォルダ>アルバムフォルダ」という構造にしてるので、ゲーム曲なんでもランダムとか、特定シリーズの順次再生とかができる。これからシリーズ名フォルダとアルバムフォルダの間にナンバリングフォルダを挟もうと思う。
    • ルートフォルダも選べるので、無駄な情報が表示されない
    • 音楽ファイルはアルバム単位とは限らないのだ…制作中楽曲のmp3、みたいな単品モノを放り込んだフォルダが輝く
    • アーティスト名が統一されているとも限らないのだ…SPITZスピッツを勝手に分けるアプリ許さん
    • アルバム名がかぶっただけで同じアルバム扱いにしてくるプレイヤーもあるのだ…花鳥風月(スピッツ)と花鳥風月(レミオロメン)を勝手に混ぜるアプリ許さん
  • 日本語ファイル名も問題なく表示される
    • 海外製だと文字化けしたり中華文字になったりすることが多い
  • 曲の切り替わり時、謎のフェードアウト・フェードインが起こらない
    • 逆にあれが実装されているプレイヤーが意外と多いのは何なんだろう…
  • 5秒巻き戻し・早送りとかいうめっちゃくちゃ便利なボタンがある
  • 画面遷移がない
  • 表示文字サイズを変えられる
    • 一画面に表示される曲数が少なすぎて見づらいアプリも多いので…(真っ先に最小サイズにした)
  • 不要な情報が出ない(ジャケット画像とか)
  • 手持ちのBluetooth機器からの操作も問題なし

あ、これ実装されてないんだ、と思ったけどなんやかんやあまり困らなさそうなところ

  • 検索機能
  • プレイリストやお気に入り

キーボードで操作をさせる

キーボードで特別に操作をさせたい(もしくはさせたくない)場合があります。
単純にショートカットキーを作りたいとか、
方向キーでモーダルやページ自体を切り替えるとか、
F5キーを押させたくないとか…。

そういう場合は押されたキーを判別する仕組みを置いてやればOK。

$(window).on("keyup", function(e){
    // 例えば、
    // e.key で押されたキー名が、
    // e.keyCode でキーに割り振られたコードが取得できる
});

keyupは名前の通り、キーを押したあとに上がった時の判定になります。
キーを押した時点で反応するkeydownというのもあり、そちらを使うこともできますが、
keydownの場合は押しっぱなしにすると反応し続けます。
さらにkeypressというのもあるようですが、ブラウザによって挙動が異なるという場合があるそうなので
長押しを利用したいという場合以外はkeyupの方が無難ではないかと思います。

このページで何かキーを押すと、↓のエリアに表示されるようになっています。
(反応しない場合はページ内の適当なところをクリックしてフォーカスを合わせてください)
さらに、keyup時にはeを、keydown時には文字列をconsoleに出力するようにしています。


key:
code :

おまけ1:特定の要素に対してのみ有効にする

この書き方の場合、$(window)なのでページ全体が対象になりますが、
もちろん、特定のオブジェクトに対してのみ有効にさせることもできます。

実装サンプルはこちら。
テキストエリアにフォーカスを合わせてから何かキーを押すとalertが出ます。


上記サンプルのコードはこちら。単純にwindow指定から要素指定に変えているだけですね。

<textarea id="textarea"></textarea>
<script>
$("#textarea").on("keyup", function(e){
    alert("テキストエリアでキー(" + e.key + ")が押されました!!!!");
});
</script>

とはいえフォーカスが当たるかどうかが問題になってしまうのか、
入力フォーム系でしか使えなさそうですね。

div等の場合、tabindex属性を付ければ動きました。ブラウザによって若干挙動が違う可能性もありますが…

おまけ2:本来のキーの挙動をさせない

例えばスペースキーや方向キーを押してもスクロールしないようにしたい、などの場合ですね。
これは処理部分でpreventDefaultしてやればOK。

$(window).on("keyup", function(e){
    e.preventDefault();
    // その他の処理
});

おまけ3:iframeの中でも外でも使いたい

(誰得なんだ…でもちょっと苦戦したので残しておく)

<HTML>

<iframe id="iframe" src=" ... "></iframe>

<JS>

$(window).on("keyup", function(e){
    // 処理
});
$("#iframe").on("load", function(){
    $(this).contents().find("body").on("keyup", function(e) {
        // 処理
    });
});

考え方としては、iframeの中身のbodyタグ内に対してkeyupを有効にする、という感じですね。

おまけ4:Ctrl・Shift・Altとの合わせ技

例えば「Ctrlを押しながら○○を押すと…」というショートカットキーなどの用途に。
それぞれ「ctrlKey」「shiftKey」「altKey」で、押されているか否か(true/false)が取得できます。
(別途サンプルは置きませんが、このページのconsoleでkeyup時のイベントが出るようになっていますのでそちらで確認してください)

$(window).on("keyup", function(e){
    // 例えば「Shift+s」を押した場合は「false true false s」とコンソールに表示
    console.log(e.ctrlKey, e.shiftKey, e.altKey, e.key);
});

PostgreSQLで自動採番がズレる(主キー重複エラーが出る)

「何もしてないのに動かなくなった」のよくあるやつ。

アプリは何も改修してないのに、登録系処理を動かすとエラーがでるようになった…
ログを見てみるとDuplicate Keyしてる。
いや、ここのPKはsequenceじゃん。なんで???

となったときにはほぼ確実に
「sequenceの値が更新されておらず、古いのを使おうとして重複してる」
というパターン。

なんでそんなことになるのかはいまいち分かっていませんが、
テストデータをざっくりINSERTしたりした後に発生しやすい気がします。

とにかく、sequenceの値を新しくしてやればいいので、以下クエリをぶん投げればOK。

SELECT SETVAL('sequence名', (SELECT MAX(PK名) FROM テーブル名));

以下のクエリでPKの最大値を取れるので、それをsequenceにsetしている、という感じですね。
ということで、データをごっそり削除したあとでsequenceもリセットしたい、という場合にも使えるはず。

SELECT MAX(PK名) FROM テーブル名