アナログCPU:5108843109

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

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

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 テーブル名

ドラッグ&ドロップで項目の並べ替えを可能にする

まずはサンプルから。

hoge」「fuga」「piyo」の文字列をドラッグ&ドロップで並べ替えることができます。

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


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

これ、どんだけめんどくさい実装なのかと思ったらめちゃくちゃ簡単でした。

jQuery使用してます。jquery-uiもいります。

<script src=" ... /jquery.min.js"></script>
<script src=" ... /jquery-ui.js"></script>

<HTML>

<ul class="sortable">
  <li id="1">hoge</li>
  <li id="2">fuga</li>
  <li id="3">piyo</li>
</ul>

<JS>

$(function() {
    $(".sortable").sortable();
});

以上。まじかよ。すごい。

ちなみにスマホ対応したいときは、↓をDLしてincludeするだけで済むっぽい。まじかよすごい。
jQuery UI Touch Punch - Touch Event Support for jQuery UI

<script src=" ... /jquery.ui.touch-punch.min.js"></script>

おまけ:ドロップしたときの処理を作る

正確にはドロップによって並びを変更したときの処理ですが。
JS側を以下のような形に変更すればOK。

<JS>

$(function() {
    $(".sortable").sortable({
        update: function(){
            // ここにドロップ時処理
        }
    });
});

ここで随時ajaxで保存するも良し、submit用の配列なりテキストなりをこの時点で作っておくも良し。
パズルゲームとか作れそうだな。

JSとPHPでJSONデータを扱う

WEBアプリを作っていると、JSとPHPの間のデータのやり取りなどでJSON形式を使うことが多いので、
JSONを配列にしたり、配列をJSONにしたりする方法をメモ。

PHPで配列をJSONにする

json_encodeを使います。
PHP: json_encode - Manual
変換したい配列以外にもオプションがありますが、基本的に無指定でOK。

<?
$data_array = array(
    'hoge' => 1,
    'fuga' => 2,
);
$data_json = json_encode($data_array);

PHPJSONを配列にする

json_decodeを使います。
PHP: json_decode - Manual
第二引数を無指定(またはfalse)にするとオブジェクト形式になり、
trueを渡すと連想配列になります。
個人的には配列が良いので常にtrueを渡しています。

<?
$data_json = '{"hoge":1,"fuga":2}';
$data_array = json_decode($data_json, true);

JSで配列をJSONにする

JSON.stringifyを使います。

var data_array = { hoge: 1, fuga: 2 };
var data_json = JSON.stringify(data_array);

JSでJSONを配列にする

jQueryなら$.parseJSONを、生JSなら…なんやこれ。

jQuery

var data_json = '{"hoge":1,"fuga":2}';
var data_array = $.parseJSON(data_json);

<JS>

var data_json = '{"hoge":1,"fuga":2}';
var data_array = (new Function("return " + data_json))();

非同期処理を同期処理っぽく扱う

まず、以下2つの関数を用意しました。

// funcBの戻り値と"funcA"を吐き出す関数
function funcA(){
    console.log(funcB());
    console.log("funcA");
}

// 開始から5秒後に「funcB」とreturnする関数
function funcB(){
    setTimeout(function(){
        return "funcB";
    },5000);
}

期待としては、実行から5秒後に「funcB」と「funcA」が
(ほぼ)同時に表示されてほしいわけですが、まあそういうわけにはいきません。
setTimeoutは「5秒後に○○という処理をする」というタイマー的なものをセットしているだけなので。
具体的には、実行と(ほぼ)同時に

undefined
funcA

と表示されます。
その5秒後くらいにfuncBが返している値は闇に消えます。

ここまで簡単な例ならsetTimeout内で「funcB」「funcA」を表示すりゃいいじゃん、で済みますが
複雑になってくると困る場合もあったので、いろいろ調べて以下のように加筆修正してみました。

// funcBの戻り値と"funcA"を吐き出す関数
function funcA(){
    var def = funcB();
    def.done(function(){
        console.log(def.return_value);
        console.log("funcA");
    });
}

// 開始から5秒後に「funcB」とreturnする関数
function funcB(){
    var deferred = new $.Deferred();
    setTimeout(function(){
        deferred.return_value = "funcB";
        deferred.resolve();
    },5000);
    return deferred;
}

わーいらくちーん
deferredというのを使っています。
処理を監視して、「終了したら○○する」ということができます。

無事に、実行後5秒ほど経ってから

funcB
funcA

と表示されました。

ポイントは以下のような感じでしょうか。

  • funcA
    • funcBの戻り値を変数で受けて、「.done」で「funcB終了時の処理」を記述
  • funcB
    • Deferredオブジェクトを生成し、resolve()で処理終了したことを通知
    • Deferredオブジェクトのreturnは、時間のかかる処理の外でOK
    • Deferredオブジェクトには戻り値用の要素を勝手に追加できる
      • 上記の例では「return_value」が勝手に追加したやつ

これなら大元のロジックを大きく変えることなく実装できそう。

参考文献
jQueryのDeferredが便利過ぎた

連想配列に含まれるIDを使ってユニーク化する関数

を作ったのでメモ。

function uniqAry(ary){
    // idの値で昇順ソートする
    ary.sort(function(a, b){ return a.id > b.id; });

    // 重複しているIDがあれば後に出てきた方を削除(undefinedにする)
    var tmpid = 0;
    $(ary).each(function(i, e){
        if (e.id == tmpid){
            delete ary[i];
        }
        else{
            tmpid = e.id;
        }
    });

    // undefined(削除した項目)を除いたものを返す
    return ary.filter(function(v){ return v != undefined; });
}

配列に必ず0でない数値の「id」が含まれているという前提。

配列に含まれる「id」でソートして、
ソート後配列を順番に見て前レコードと同じIDだったら削除しています。
spliceで要素を削除するとループがめんどくさいことになるので、deleteでundefined化してからfilterしています。


例えば以下のようなのを実行すると

var ary = [
    {id: 1, name:"name1_1"},
    {id: 3, name:"name3_1"},
    {id: 1, name:"name1_2"},
    {id: 2, name:"name2_1"},
    {id: 3, name:"name3_2"},
];
console.log( uniqAry(ary) );

こうなります。

{id: 1, name:"name1_1"},
{id: 2, name:"name2_1"},
{id: 3, name:"name3_1"},

特定のクラスを持ったチェックボックスについて、チェック有無で絞り込む

jQueryセレクタ便利…。
いや、プレーンJSの書き方知らないので比較できないんですけどこれはたぶん便利なやつ…。

必要になるたびググってる気がするのでメモ。

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



チェックしているものとしていないものを分ける

(結果はコンソールで見てね)
================================
↑実装サンプルここまで

<HTML>

<input type="checkbox" class="hoge-cb" value=1>
<input type="checkbox" class="hoge-cb" value=2>
<input type="checkbox" class="hoge-cb" value=3>
<a href="#" onclick="testCheckbox()">チェックしているものとしていないものを分ける</a>

<JS>

function testCheckbox(){
    console.log( $(".hoge-cb:checked") );
    console.log( $(".hoge-cb:not(:checked)") );
}

ドラッグ&ドロップでファイルをアップロードする(ちょっとリッチ版)

こちらの記事が前提となります。

IEだと動かないはず。対応した版はこちら。
ドラッグ&ドロップでファイルをアップロードする(IE対応版) - アナログCPU:5108843109

簡単に書くと
「ファイルのアップロードフォーム」と
「アップロードしたいファイルをドロップできるエリア」を用意して
エリアにドロップされたファイルをフォームに渡す処理が既にあります。

これに対して、この記事では以下の処理を追加していきます。

  • ドロップしたら送信ボタンを押さなくてもアップロード
  • ファイル選択から選択したときもボタンを押さずにアップロード
  • ファイル選択のボタンとかかっこわるいから出さない。ドロップ用のエリアをクリックしたら選べるようにする
  • ドロップエリアにマウスが乗ってる間は色を変えるとか分かりやすくする
  • ドロップエリアの外でドロップしてもファイルが開かないようにする

これを実現するためにもうちょっと切り分けて、具体的には以下のような実装をします。

  • formを非表示にする
  • ドロップエリアをクリックしたら、formのファイル選択ボタンをクリックしたことにする
  • formのファイルinputタグが変更されたら、formの送信ボタンをクリックしたことにする
  • ドロップエリアの上にファイルを掴んで乗っかったときにエリアの色を薄くする
  • ドロップエリアでドロップされたときにエリアの色をデフォルト状態に戻す
  • ドロップエリアから離れたときにエリアの色をデフォルト状態に戻す
  • ドロップエリアの外でドロップしてもファイルが開かないようにする

こんな感じでしょうか。
順番にやっつけていきます。

続きを読む