複数のバージョンのjQueryを読んでしまったときの共存のさせ方

新人のMです。今週もよろしくお願いします。

今回は、複数のバージョンのjQueryを読まないといけないときの対処方法について書きたいと思います。1.7系でしか動かないコードがあるけど、1.10系も使ってみたい場合やajaxで取得したページにjQueryを再取得してしまってる場合などにお試しください(※推奨できる方法ではないので、実装を見直すべきですが)

2個目のjQueryを読む前に処理したい場合

古いjQueryを別の変数に退避させて、新しいjQueryを読む方法です。

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
$old = jQuery;
</script>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
console.log($old().jquery); // => 1.7.2
console.log($().jquery); // => 1.10.2
console.log(jQuery().jquery); // => 1.10.2
</script>

2個目のjQueryを読んだあとに処理したい場合

新しいjQueryを読んだあとに、noConflict([removeAll])で古いjQueryを復活させる方法です。removeAllのオプションにtrueを渡すと$オブジェクトだけではなく、jQueryのオブジェクトも元に戻されます。

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
$new = jQuery.noConflict(true);
console.log($().jquery); // => 1.7.2
console.log(jQuery().jquery);
// removeAll is true => 1.7.2
// removeAll is false => 1.10.2
console.log($new().jquery); // => 1.10.2
</script>

まとめ

複数のバージョンのjQueryを読まないといけないときの対処方法について紹介しました。どうしても複数のバージョンのjQueryを共存させないといけないときなどにご活用ください。

javascriptで日付を扱うときに便利なmoment.jsの紹介

新人のMです。 このアドベントカレンダーもなんとか1周間続けることができました。残り3週間がんばっていきたいと思います。

今回は、javascriptで日時を扱うときに便利なライブラリの紹介を行いたいと思います。 javascriptにもDateオブジェクトはあるのですが、使いづらく簡単な処理であればStringで代用してしまったりします。そこで、試してみたいのが、今回紹介するmoment.jsです。

momentオブジェクト生成

日時情報を保持するオブジェクトです。任意のフォーマットパターンで日時文字列をparseすることができます。

moment();
// => 現在日時のオブジェクト

moment("2013/12/8", "YYYY/M/D");
moment("Dec 8, 2013", "MMM D, YYYY");
moment("8 12 2013", "D M YYYY");
// => 2013年12月8日のオブジェクト

フォーマット出力

任意のフォーマットパターンでStringを出力できます。

moment().format("MMM D YYYY ddd, hh:mm:ss a Z");
// => "Dec 8 2013 Sun, 09:05:04 pm +09:00"

日本語化

langs付きのmomentなら、lang("ja")で日本語に出力してくれます。また、langの設定を別に行うこともできます。

moment.lang("ja", {
    weekdaysShort: ["日","月","火","水","木","金","土"]
});
moment.format("ddd");
// => 日

まとめ

javascriptで日時を扱うときに便利なライブラリであるmoment.jsの簡単な紹介を行いました。 moment.jsには、他にも日付のマニピュレーションの機能が豊富にあったりするので、日付関係で困ったときは試してみてはいかがでしょう。

javascriptでもpythonのdecoratorを使いたい

新人のMです。 学生時代は、pythonをいじってたりしたので、今回はpythonの機能からjsで実装できそうなものを作ってみたいと思います。

pythonのdecorator

関数の処理の前後に任意の処理を飾り付けれる機能のことです。いわいるデコレータパターンだと思います。

def deco(opt):
    def wrapper(func):
        def impl(*args, **kwargs):
            print args, kwargs, opt
            print "before"
            r = func(*args, **kwargs)
            print "after"
            return r + opt
        return impl
    return wrapper

@deco(1)
def f(a):
    print a
    return a
f(2)
=> 3

javascriptでの実装

var deco = function() {
    var args = arguments;
    var wrapper = function(fn) {
        var impl = function() {
            console.log("decorator arg", args, "wraper arg", arguments);
            console.log("preprocess");
            var r = fn.apply(this, Array.prototype.slice.call(arguments));
            console.log("postprocess");
            return r + ":" + Array.prototype.join.call(args);
        }
        return impl;
    }
    return wrapper;
};

var f = deco(1)(function() {
        console.log(arguments);
        return Array.prototype.join.call(arguments);
f(2, 3);
=> "2,3:1"

まとめ

javascriptpythonのdecoratorを実装例を示してみました。 デコレータを使うことで、定型的な前処理・後処理をまめることができると思います。

CSSでくるくる回るアニメーション

新人のMです。 ネタ探しが大変です… 今日もCSSについて書こうと思います。 CSSアニメーションが簡単にアニメーションを表現できそうで興味があるので、試しに簡単なインジケータをCSSの@keyframesを使って作ってみたいと思います。

@keyframes

ある時点での状態を指定したキーフレームを複数用意することでアニメーションを表現します。

@keyframes 名前 {
    0% {}
    100% {
        transform: rotate(360deg);
    }
}

くるくる回るインジケータ

<html>
<head>
<style type="text/css">
@-webkit-keyframes anime {
    0% {}
    100% {
        -webkit-transform: rotate(360deg);
    }
}
.indicator {
    display: inline-block;
    position: relative;
    background: pink;
    margin-left: 50px;
    width: 20px;
    height: 100px;
    -webkit-border-radius: 5px;
    -webkit-animation: anime 3s infinite linear;
}
.indicator:before, .indicator:after{
    content: "";
    width: 20px;
    height: 100px;
    position: absolute;
    background: pink;
    opacity: 0.3;
    -webkit-border-radius: 5px;
    -webkit-transform: rotate(-60deg);
}
.indicator:after {
    opacity: 0.7;
    -webkit-transform: rotate(60deg);
}
</style>
</head>
<body>
    <div class="indicator"></div>
</body>
</html>

単調にオブジェクトが1回転するアニメーションを定義し、それを3秒で1回行うように設定しました。残像を表現したくて、バーの前後に薄いバーを追従させるようにしてみたのですが、同じスピードで回してるからか、残像ぽくないですね…(色をピンクにしたら、花が回ってるようでかわいいので、これはこれでありですが) ※Chrome以外で試すときは、ベンダープリフィックス(-webkit-)を各ブラウザのものに書き換えてください。

まとめ

CSS3の@keyframesを使うことで、CSSだけでアニメーションを実装しました。

:before擬似要素と:after擬似要素

新人のMです。 毎日ネタ考えるの大変ですね。

jsの話が続いてるので、今日はCSSの話にしてみたいと思います。

:before擬似要素と:after擬似要素

対象の要素の前後に擬似的な内容を追加してくれる擬似要素です

このような形で指定すると、「beforePafter]のように表示されます。

<html>
<head>
<style type="text/css">
p:before {
    content: "before";
}
p:after {
    content: "after";
}
</style>
</head>
<body>
    <p>P</p>
</body>
</html>

contentには、文字列の他に、URL(画像)、要素の属性値、カウンタが指定できます。 例えば、リンクの前にアイコンを表示させたり、リンクの後ろにURLを表示させたり、タイトルの前後に飾りをつけたりするのに使えます。

簡単Tooltip

:hover擬似クラスといっしょに使うと簡単にTooltipが実装できたりします。

<html>
<head>
<style type="text/css">
.content {
    display: inline;
    position: relative;
}
.content:hover:after {
    content: attr(data-content);
    background: yellow;
    position: absolute;
    top: 50%;
    left 50%;
}
</style>
</head>
<body>
   <p class="content" data-content="content">P</p>
</body>
</html>

要素にマウスをかざすと、説明が要素の上に表示されます。

まとめ

:before擬似要素と:after擬似要素の簡単な紹介を行いました。 簡単なTooltipの作り方の紹介を行いました。

event.curretTargetとevent.targetの違い

新人のMです。 今回も短めの記事で行きます。

イベントが発火した要素の取得の仕方

イベントが発火したときに、イベントリスナにイベントオブジェクト(最初の引数)が渡されます。 このオブジェクトにどの要素でイベントが発火したのか示すプロパティが2種類あります。 その2種類event.currentTargetとevent.targetの違いについて見て行きたいと思います。

エレメント.addEventListener(イベント, function(e) {}, false);
$(セレクタ).on(イベント, function(e) {});

event.currentTarget

イベントリスナをバインドした要素をイベントが通過した時の要素(イベントリスナがバインドされてる要素自身)を表します

event.target

イベントが発生した要素を表します。

以下の例で説明します。 青い部分をクリックすると、".outer"にバインドしたイベントリスナに「currentTarget=".outer"」、「target=".outer"」なイベントオブジェクトが渡されます。 他の色の部分をクリックすると、".inner"にバインドしたイベントリスナに「currentTarget=".inner"」、「target=".inner"」なイベントオブジェクト、".outer"にバインドしたイベントリスナに「currentTarget=".outer"」、「target=".inner"」なイベントオブジェクトが渡されます。

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<style type="text/css">
.outer {
    width: 100px;
    height: 100px;
    background: blue;
}
.inner {
    width: 50px;
    height: 25px;
}
.inner:nth-child(1) {
    background: pink;
}
.inner:nth-child(2) {
    background: purple;
}
.inner:nth-child(3) {
    background: orange;
}
.inner:nth-child(4) {
    background: green;
}
</style>
<script type="text/javascript">
$(document).on("click", ".outer", function(e) {console.log(e.currentTarget, e.target);});
$(document).on("click", ".inner", function(e) {console.log(e.currentTarget, e.target);});
</script>
</head>

<body>
    <div class="outer">
        <div class="inner"></div>
        <div class="inner"></div>
        <div class="inner"></div>
        <div class="inner"></div>
    </div>
</body>
</html>

まとめ

event.currentTargetとevent.targetの違いについて見てみました。 currentTarget=バインドした要素、target=イベントが発生した要素と覚えておくと簡単かと思います。 currentTargetのほうがバインドした要素を表しているのでイベントリスナを書くときには、わかりやすいと思います。

underscore.jsで気になる関数(Functions、Objects、Utility、Chaining編)

前回の続きです。今日はUnderscore.jsのFunctions、Objectsを中心に見ていきます。

Functions

FPぽいことするのに便利な関数が揃ってます。

_.memoize(function, [hashFunction])

メモ化関数です。関数の計算結果を記憶しておいて、再計算のコストを低くしてくれます。フィボナッチ数列を計算するのに便利そうです。

var fibonacci = _.memoize(function(n) {
  return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});

_.once(function)

関数を一度しか計算しない。初期化処理とかに便利そうです。

var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.

_.after(count, function)

count回関数が呼び出されて初めて、関数が実行されます。非同期の処理実行後に処理を行いたいときに便利そうです。

var renderNotes = _.after(notes.length, render);
_.each(notes, function(note) {
  note.asyncSave({success: renderNotes});
});
// renderNotes is run once, after all notes have saved.

_.wrap(function, wrapper)

関数の前後に処理を行えます。pythonのdecoratorぽいことができそう?

var hello = function(name) { return "hello: " + name; };
hello = _.wrap(hello, function(func) {
  return "before, " + func("moe") + ", after";
});
hello();
=> 'before, hello: moe, after'

_.compose(*functions)

関数合成をしてくれる関数です。かっこたくさん書かなくていいのは、楽です。

var greet    = function(name){ return "hi: " + name; };
var exclaim  = function(statement){ return statement.toUpperCase() + "!"; };
var welcome = _.compose(greet, exclaim);
welcome('moe');
=> 'hi: MOE!'

Objects

_.omit(object, *keys)

keysに指定したプロパティを除外してくれます。chainで使うと便利です。

_.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid');
=> {name: 'moe', age: 50}

_.defaults(object, *defaults)

デフォルトのプロパティを設定してくれます。

var iceCream = {flavor: "chocolate"};
_.defaults(iceCream, {flavor: "vanilla", sprinkles: "lots"});
=> {flavor: "chocolate", sprinkles: "lots"}

_.tap(object, interceptor)

_chainといっしょに使うと便利です。計算途中の確認に使えます。

_.chain([1,2,3,200])
  .filter(function(num) { return num % 2 == 0; })
  .tap(alert)
  .map(function(num) { return num * num })
  .value();
=> // [2, 200] (alerted)
=> [4, 40000]

Utility

_.result(object, property)

objectのpropertyが関数なら結果を返して、値ならその値を返してくれます。

var object = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }};
_.result(object, 'cheese');
=> "crumpets"
_.result(object, 'stuff');
=> "nonsense"

Chaining

underscore関数がメソッドチェーンできるので便利です。

var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}];
var youngest = _.chain(stooges)
  .sortBy(function(stooge){ return stooge.age; })
  .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
  .first()
  .value();
=> "moe is 21"

まとめ

2回にわたって、javascriptのユーティリティライブラリであるunderscore.jsのおもしろそうな関数の紹介を行いました。 underscore.jsは、ファイルサイズが小さく(minify&gzipで4.9kb)、実績も豊富(bakcbone.jsの依存ライブラリなのでHulu、foursquareなど)、ドキュメントもわかりやすく、おすすめです。

underscore.jsで気になる関数(collections、arrays編)

2回目にして、もうネタ切れ気味になってきた新人のMです。

ネタ切れ気味なので、今日は軽めにUnderscore.jsで気に入ってる関数を幾つか紹介します。

Collections

一般的なmap・reduce・filter系ですが、jsのmap関数はArrayのメソッドだったりするので、Hashにも適用できるのは便利です。特に便利だと思うものをピックアップします。

_.pluck(list, propertyName)

プロパティ名に指定したものをmapしてくれます。

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.pluck(stooges, 'name');
=> ["moe", "larry", "curly"]

_.groupBy(list, iterator, [context])系

iteratorの返り値でグルーピングしてくれます。

_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
=> {1: [1.3], 2: [2.1, 2.4]}

_.groupBy(['one', 'two', 'three'], 'length');
=> {3: ["one", "two"], 5: ["three"]}

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.indexBy(stooges, 'age');
=> {
  "40": {name: 'moe', age: 40},
  "50": {name: 'larry', age: 50},
  "60": {name: 'curly', age: 60}
}

_.countBy([1, 2, 3, 4, 5], function(num) {
  return num % 2 == 0 ? 'even': 'odd';
});
=> {odd: 3, even: 2}

Arrays

_.without(array, [*values])

arrayからvaluesに含まれるものを除外したArrayを返してくれます。chainで使うと便利です。

_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]

_.union(*arrays)

和を取ってくれます

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

_.intersection(*arrays)

積を取ってくれます

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]

_.difference(array, *others)

差を取ってくれます。処理の前後で追加・削除の検出に便利です。

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

_.uniq(array, [isSorted], [iterator])

重複を取ってくれます

_.uniq([1, 2, 1, 3, 1, 4]);
=> [1, 2, 3, 4]

_.range([start], stop, [step])

一般的なrange関数です

_.range(10);
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11);
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5);
=> [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1);
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0);
=> []

一旦まとめ

Functions、Objects、Utilityにも便利な関数がたくさんあるのですが、長くなりそうなので、今日はこのへんで。

Collections、Arraysには最近の言語だと標準関数で備わってるものが多いですが、今のjsだと使いにくいものも多いので、こういったライブラリで補完すると大変楽です。

underscore.jsは、一般的に使われてる便利なutilityライブラリです。聞いたことあるけど、まだ使ってないって方はこの機会に導入を検討してみてはいかがでしょうか?

セレクトボックスのoptionを書き換えるjQueryプラグイン

こんにちは、こんばんは、新人のMです。 アドベントカレンダーを始めたはいいものの12/1が終わるまで時間がないので、簡単なネタで行きたいと思います。

セレクトボックスの内容を動的に書き換えたいことが、よくあるのですが、そんなときに使えるjQueryプラグインを書いてみました。 数十行なので読んでいただいたら、わかると思いますが、すこし説明します。

使い方

こんな感じに、hashの配列を渡してあげると、指定したセレクトボックスのoptionを書き換えてくれます。

var a = [
    { text: "a", value: "1"},
    { text: "b", value: "2", "data-b-c": "b"},
    { text: "c", value: "3", selected: true}
];
$("select").simpleOptions(a);

書き換えてくれる属性は、今のところ以下のものになります。

  • text
  • value
  • selected
  • disabled
  • data-*

他の属性も書き換えたいときは、適宜コードに追加してくだい。

セレクトボックスのvalueが変わったら、changeイベントを発火するようにしてあります。

コード

2番目のスクリプトタグ内のコードをコピペしてお試しください。

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
(function($) {
    var simpleOptions = function(arr) {
        var $options = this.find("option");
        var selected = this.val();
        var diff = arr.length - $options.length;

        if (diff < 0) $options.slice(diff).remove();
        else if (diff > 0) {
            var fragment = document.createDocumentFragment();
            for (var i = diff; i; --i)
                fragment.appendChild(document.createElement("option"));
            this.append(fragment);
        }
        var some = arr.some(function(v) { return !!v.selected;});
        this.find("option").each(function(i, v) {
            v.value = arr[i].value;
            v.text = arr[i].text;
            v.selected = some ? !!arr[i].selected : ""+arr[i].value === selected;
            v.disabled = !!arr[i].disabled;
            for (var k in v.dataset)
                delete v.dataset[k];
            for (var k in arr[i])
                if (/^data-.+/.test(k))
                    v.setAttribute(k, arr[i][k]);
        });
        if (this.val() !== selected) this.change();
        return this;
    };

    $.fn.simpleOptions = simpleOptions;
})(jQuery);
</script>

<script type="text/javascript">
$(function() {
    $("select").on("change", function() {console.log(this);});
    var a = [
        { text: "a", value: "1"},
        { text: "b", value: "2", "data-b-c": "b"},
        { text: "c", value: "3", selected: true}
    ];
    $("select").simpleOptions(a);
});
</script>
</head>

<body>
    <select style="width: 100px">
        <option data-test="test"></option>
        <option data-test="test"></option>
        <option data-test="test"></option>
        <option data-test="test"></option>
    </select>
</body>
</html>

注意

DOMを使いまわしてるので、option自体に何かイベントを割り当てたときは、正しく動作しないので、ご注意ください。

まとめ

セレクトボックスのoptionを書き換えてくれるjQueryプラグインを作りました。 やっつけ感はありますが、大抵の場合はこれで事足りると思います。(アドバイスがあればお願いします)

GSOLエンジニアblog はじめました。

はじめまして、GSOLエンジニアblogの運用を任されたMです。

この度、遅ればせながら、グローバル・ソリューションズにおいてもエンジニアblogを開設することとなりました。このblogでは、弊社エンジニアが、開発時のTipsやノウハウ、興味ある技術、弊社の製品の紹介などを書いていく予定です。

このblogをきっかけに、弊社のことにご興味をもっていただけたら幸いです。
よろしくお願いします。


12月といえば技術系blogでは、アドベントカレンダーの季節ですね。弊社(むしろ私個人)としてもこの流れに乗っておきたいなと思い、1エントリ目の記事からアドベントカレンダーの記事としていと思います。
それでは、はじめます。