やるしかなっちゃん

やるしかない!

jQuery非依存の画面分割ライブラリSplit.jsを使ってみる

ふとした拍子に画面を分割したくなることがあると思いますが、大抵のライブラリはjQuery依存だったりメンテナンスが止まっていたりします。
そんな辛い状況の中、結構良さげなSplit.jsというものを発見しました。 github.com jQueryに依存せず軽量で中身も今風のJSで書かれています。

セットアップ

Split.jsと最低限必要なCSSを用意するだけです。

$ yarn add split.js
又は
$ npm install --save split.js
/* 分割のスタイル */
.split {
  box-sizing: border-box;
  overflow-y: auto;
  overflow-x: hidden;

  &.split-horizontal {
    height: 100%;
    float: left;
  }

}

/* 仕切りのスタイル*/
.gutter {
  background-color: #eee;
  background-repeat: no-repeat;
  background-position: 50%;

  &.gutter-vertical {
    background-image:  url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=');
    cursor: ns-resize;
  }

  &.gutter-horizontal {
    background-image:  url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
    cursor: ew-resize;
  }

  &.gutter-horizontal {
    height: 100%;
    float: left;
  }

}

2分割

f:id:k213:20180610220513g:plain

HTML
各画面をwrapするdiv、各画面のdiv、仕切りのdivを用意するだけで簡単に分割ができます。

<div class="two-horizontal-split clearfix">
  <div class="left split split-horizontal">
    <!-- put truth html code --> 
  </div>
  <div class="gutter gutter-horizontal"></div>
  <div class="right split split-horizontal">
    <!-- put truth html code -->
  </div>
</div>

JavaScript
Splitに各画面を特定できるセレクタの配列とオプションを渡すだけです。
オプションのsizeは初期表示幅(単位は%)、minSizeは最小幅(単位はpx)です。
その他にも仕切りのサイズやドラッグ時のイベントハンドラ等のオプションがあります。

import Split from "split.js";

Split(['.two-horizontal-split .left', '.two-horizontal-split .right'], {
  sizes: [50, 50],
  minSize: [200, 200],
});

CSS
わかりやすいように見栄えを整えているだけなので略します。

.clearfix::after{
  content: "";
  display: block;
  clear: both;
}

.two-horizontal-split {
   height: 250px;
   border: 1px solid #ddd;
   border-radius: 4px;

   .left {
     background: red;
   }

   .right {
     background: yellow;
   }
}

3分割

f:id:k213:20180611001325g:plain

2分割ができれば3分割はdivタグを増やすだけで実現できます。

<div class="three-horizontal-split clearfix">
  <div class="left split split-horizontal">
    <!-- put truth html code -->
  </div>
  <div class="gutter gutter-horizontal"></div>
  <div class="center split split-horizontal">
    <!-- put truth html code -->
  </div>
  <div class="gutter gutter-horizontal"></div>
  <div class="right split split-horizontal">
    <!-- put truth html code -->
  </div>
</div>
import Split from "split.js";

Split(['.three-horizontal-split .left', '.three-horizontal-split .center', '.three-horizontal-split .right'], {
  sizes: [33, 34, 33],
  minSize: [200, 200, 200]
});
.three-horizontal-split {
   height: 250px;
   border: 1px solid #ddd;
   border-radius: 4px;

   .left {
     background: red;
   }

   .center {
     background: blue;
   }

   .right {
     background: yellow;
   }
}

垂直2分割

f:id:k213:20180611001856g:plain

垂直方向の分割はdirectionオプションにverticalを指定するだけです。

<div class="two-vertical-split">
  <div class="top split">
    <!-- put truth html code -->
  </div>
  <div class="gutter gutter-vertical"></div>
  <div class="bottom split">
    <!-- put truth html code -->
  </div>
</div>
import Split from "split.js";

Split(['.two-vertical-split .top', '.two-vertical-split .bottom'], {
  direction: 'vertical',
  minSize: [50, 50]
});
.two-vertical-split {
  height: 250px;
  border: 1px solid #ddd;
  border-radius: 4px;

  .top {
    background: red;
  }

  .bottom {
    background: yellow;
  }
}

4分割

f:id:k213:20180611004144g:plain

ここまでの知識を総動員するだけで4分割も実現できます。
ひたすらdivをネストしていきましょう。

<div class="four-split-wrap clearfix">
  <!-- 上 -->
  <div class="top">
    <!-- 左上 -->
    <div class="top-left split split-horizontal">
      <!-- put truth html code -->
    </div>
    <div class="gutter gutter-horizontal"></div>
    <!-- 右上 -->
    <div class="top-right split split-horizontal">
      <!-- put truth html code -->
    </div>
  </div>

  <div class="gutter gutter-vertical"></div>

  <!-- 下 -->
  <div class="bottom">
    <!-- 左下 -->
    <div class="bottom-left split split-horizontal">
      <!-- put truth html code -->
    </div>
    <div class="gutter gutter-horizontal"></div>
    <!-- 右下 -->
    <div class="bottom-right split split-horizontal">
      <!-- put truth html code -->
    </div>
  </div>

</div>
import Split from "split.js";

Split(['.four-split-wrap .top', '.four-split-wrap .bottom'], {
  direction: 'vertical',
  minSize: [50, 50]
});
Split(['.four-split-wrap .top .top-left', '.four-split-wrap .top .top-right'], {
  sizes: [50, 50],
  minSize: [200, 200]
});
Split(['.four-split-wrap .bottom .bottom-left', '.four-split-wrap .bottom .bottom-right'], {
  sizes: [50, 50],
  minSize: [200, 200]
});
.four-split-wrap {
  height: 250px;
  border: 1px solid #ddd;
  border-radius: 4px;

  .top-left {
    background: red;
  }

  .top-right {
    background: yellow;
  }

  .bottom-left {
    background: blue;
  }

  .bottom-right {
    background: green;
  }

}

まとめ

ここまでのコードは全て↓に置いておきます。
https://github.com/k213/playground/tree/master/css/split-view

他にもインスタンス経由での操作用のAPIも存在するので詳しくはドキュメントを参照してみてください。

JavaScriptでインスタンスメソッドの動的呼び出し

Pythonではインスタンスメソッドを動的に呼び出すにはgetattrを使えば実現できる

class Hello:
  def greet(self):
    print("hello~")

  def run(self, name):
    method = getattr(self, name)
    method()

hello = Hello()
hello.run("greet") # hello~

JavaScriptで同じことをやりたい時によくわからなかったので次の様に実装した

class Hello {
  greet() {
    console.log("hello~");
  }

  run(name) {
    this[name].call(this);
  }
}

const hello = new Hello();
hello.run("greet"); // hello~

あってるのかこれ?

シェルスクリプトでフォルダ監視

止むにやまれぬ事情があって題名の通りのことをするハメになった

最近はどんなツールにもwatchオプションがあるし、一昔前でもgulp-watch使ってたしまさかこんな原始人みたいなことをするハメになるとは思いもしなかった

方針は単純で監視対象のフォルダのサイズが変更したかどうかで変更を検知している

#!/bin/bash

# 監視対象のディレクトリ
targets=(/Sample/Example/Dir1 /Sample/Example/Dir1)

# 実行するコマンド
command="ls"

# 変更検知用の配列
prev_sizes=()
for target in "${targets[@]}"; do
  size=`du -bsx $target | awk '{print $1}'`
  prev_sizes+=($size)
done

# 監視間隔
INTERVAL=1

while true; do

  sleep $INTERVAL

  for ((i = 0; i < ${#targets[@]}; i++)) {
      size=`du -bsx ${targets[$i]} | awk '{print $1}'`

      if [ "${prev_sizes[$i]}" != "$size" ]; then
        eval $command
        echo "Changed: ${targets[$i]}"
        echo "Done: $command"

        prev_sizes[$i]=$size
      fi

  }

done

シェルスクリプト全然書いたことないからこれが正しいのかまったくわからない
無念だ

JavaScriptの型判定

typeof

typeofは色々と使いにくいです
特にnew Hoge()したものは'object'になってしまいます

// 正しく判定できるパターン
typeof 1         // 'number'
typeof '1'       // 'string'
typeof true      // 'boolean'
typeof undefined // 'undefined'

// 'object'になってしまうパターン
typeof null            // 'object'
typeof []              // 'object'
typeof new String('1') // 'object'
typeof new Date()      // 'object'

Object.prototype.toString()

オブジェクトクラスの検出にはObject.prototype.toString()を使った方が正確です
Object.prototype.toString() - JavaScript | MDN

Object.prototype.toString.call(1)               // '[object Number]'
Object.prototype.toString.call(null)            // '[object Null]'
Object.prototype.toString.call(undefined)       // '[object Undefined]'
Object.prototype.toString.call([])              // '[object Array]'
Object.prototype.toString.call(new String('1')) // '[object String]'
Object.prototype.toString.call(new Date())      // '[object Date]'

まとめ

以上より型判定を行い時はObject.prototype.toString()を使いましょう
ちなみに↓のようにsliceをしておけば型名だけを取り出せます

Object.prototype.toString.call(1).slice(8, -1) // 'Number'

おまけ(NaNの判定)

Object.prototype.toString.call(NaN).slice(8, -1)は'Number'になります
なのでisNaNを使うしかないのですが、トップレベルのisNaNはあまり厳密ではないです

isNaN(NaN)       // true
isNaN(undefined) // true
isNaN("hoge")    // true

isNaNの引数が数値出ない時(Number(引数)の結果がNaNになる時)にtrueを返します
そうではなく引数がNaNである時にtrueを返すのがNumber.isNaNです
Number.isNaNは純粋にNaNであるかどうかを判定できます

Number.isNaN(NaN)       // true
Number.isNaN(undefined) // false
Number.isNaN("hoge")    // false

lessのcalcで異なる単位同士の計算をすると値がおかしくなる

題名の通りのlessのcalcにとんでもない落とし穴があって今日見事にハマってしまった。
下のように%とpxの計算を書く。

width: calc(100% - 90px);

これをCSSコンパイルすると100% - 90%になる(;´Д`)(;´Д`)

width: calc(10%);

どうやらコレは有名な不具合らしく解決策としては以下のようにエスケープすれば良いらしい。

width: calc(~"100% - 90px");

Facebookのアクセストークンをlocalhostで取得する方法

開発者登録の時にアプリドメインを指定するとそのドメインが認証の対象になるので、そのドメインならアクセストークンの取得ができるみたい

でもこのアプリドメインにはlocalhostを指定できないのでこれは困ったと思ったら簡単に解決できた

開発者画面の設定 -> 詳細設定 -> クライアントOautn設定から有効なOauthリダイレクトURLにlocalhostのURLを指定すればよいだけだった

f:id:k213:20160426005426p:plain

↑ここの場所ね

curlでGET/POST/PUT/DELETE

最近wgetからcurlに改宗した
取り敢えずGET/POST/PUT/DELETEのリクエストを投げられたら勝ちだと思う

GETはcurlコマンドの後にURLでOK

$ curl http://www.example.com/

他のメソッドは-Xオプションの後にメソッド名を書けばOK

$ curl -X POST http://www.example.com/
$ curl -X PUT http://www.example.com/
$ curl -X DELETE http://www.example.com/

POSTでデータを送信するには-dオプションの後に書けばOK
ファイルデータの場合にはファイル名の前に@を付けるだけ

$ curl -X POST -d "hoge=0&fuga=1" http://www.example.com/
$ curl -X POST -d @hoge.json http://www.example.com/

完全勝利してしまった