ドラッグ&ドロップで列を入れ替えられるようにする
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でした"); }
サンプル:これを押すと出ます。
ページ離脱時に警告を出す
あのウザいやつ。意外と実装は簡単でした。
ただ、↓のように指定したメッセージってあんまり表示されないような…。
FirefoxとChromeではブラウザ固有のメッセージだったので、似たような意味合いのものを一応入れておくか…くらいでよいかも。
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 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 $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
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
================================
↑実装サンプルここまで
フォルダツリー型のAndroid音楽アプリ「LISNA」が最高だった
久しぶりに「お布施させてほしい」系アプリを見つけた感。
(というかこれ系のアプリは過去にもいろいろ探してたのになんで見つからなかったんだろう…不思議…)
フォルダツリー型であるだけで大正義なのに、欲しい機能がほぼ過不足なくきっちり揃ってて最高。
良かったところ(良かった順)
- フォルダツリー最高
- 好きな階層内に絞った順次再生やランダム再生ができる
- 例えばゲームサントラだと「ゲーム曲フォルダ>シリーズ名フォルダ>アルバムフォルダ」という構造にしてるので、ゲーム曲なんでもランダムとか、特定シリーズの順次再生とかができる。これからシリーズ名フォルダとアルバムフォルダの間にナンバリングフォルダを挟もうと思う。
- ルートフォルダも選べるので、無駄な情報が表示されない
- 音楽ファイルはアルバム単位とは限らないのだ…制作中楽曲のmp3、みたいな単品モノを放り込んだフォルダが輝く
- アーティスト名が統一されているとも限らないのだ…SPITZとスピッツを勝手に分けるアプリ許さん
- アルバム名がかぶっただけで同じアルバム扱いにしてくるプレイヤーもあるのだ…花鳥風月(スピッツ)と花鳥風月(レミオロメン)を勝手に混ぜるアプリ許さん
- 好きな階層内に絞った順次再生やランダム再生ができる
- 日本語ファイル名も問題なく表示される
- 海外製だと文字化けしたり中華文字になったりすることが多い
- 曲の切り替わり時、謎のフェードアウト・フェードインが起こらない
- 逆にあれが実装されているプレイヤーが意外と多いのは何なんだろう…
- 5秒巻き戻し・早送りとかいうめっちゃくちゃ便利なボタンがある
- 画面遷移がない
- 表示文字サイズを変えられる
- 一画面に表示される曲数が少なすぎて見づらいアプリも多いので…(真っ先に最小サイズにした)
- 不要な情報が出ない(ジャケット画像とか)
- 手持ちのBluetooth機器からの操作も問題なし
あ、これ実装されてないんだ、と思ったけどなんやかんやあまり困らなさそうなところ
- 検索機能
- プレイリストやお気に入り
キーボードで操作をさせる
キーボードで特別に操作をさせたい(もしくはさせたくない)場合があります。
単純にショートカットキーを作りたいとか、
方向キーでモーダルやページ自体を切り替えるとか、
F5キーを押させたくないとか…。
そういう場合は押されたキーを判別する仕組みを置いてやればOK。
$(window).on("keyup", function(e){ // 例えば、 // e.key で押されたキー名が、 // e.keyCode でキーに割り振られたコードが取得できる });
keyupは名前の通り、キーを押したあとに上がった時の判定になります。
キーを押した時点で反応するkeydownというのもあり、そちらを使うこともできますが、
keydownの場合は押しっぱなしにすると反応し続けます。
さらにkeypressというのもあるようですが、ブラウザによって挙動が異なるという場合があるそうなので
長押しを利用したいという場合以外はkeyupの方が無難ではないかと思います。
このページで何かキーを押すと、↓のエリアに表示されるようになっています。
(反応しない場合はページ内の適当なところをクリックしてフォーカスを合わせてください)
さらに、keyup時にはeを、keydown時には文字列をconsoleに出力するようにしています。
おまけ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」の文字列をドラッグ&ドロップで並べ替えることができます。
↓実装サンプルここから
================================
- hoge
- fuga
- piyo
================================
↑実装サンプルここまで
これ、どんだけめんどくさい実装なのかと思ったらめちゃくちゃ簡単でした。
<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);
PHPでJSONを配列にする
json_decodeを使います。
PHP: json_decode - Manual
第二引数を無指定(またはfalse)にするとオブジェクト形式になり、
trueを渡すと連想配列になります。
個人的には配列が良いので常にtrueを渡しています。
<? $data_json = '{"hoge":1,"fuga":2}'; $data_array = json_decode($data_json, true);