【jQuery】 IEでhtml5要素を含む文字列をappend()するとcssが適応されない問題を解決!

どういうことかというと。

jQueryhtml5要素を含む文字列をappend(), とは以下のこと。

$("ul").append("<li><article>俺のスタイル貫くぜ</article></li>");

こうするとarticle要素のcssが適応されていない!( IE8 or lower )

ちなみに、
おんなじappendでもjQueryオブジェクトをappend、

$("ul").append(
     $(document.createElement("li")).append(
         $(document.createElement("article")).text("俺のスタイル貫くぜ")
     )
);

これは、うまくいく。


appendChild自体はうまくいくかどうかやってみるんだけど、

var html5Element = document.createElement("article");
html5Element.innerHTML = "俺のスタイル貫くぜ";
$("ul").get(0).appendChild(
     document.createElement("li").appendChild(html5Element)
);

これもうまくいく。

article部分だけ文字列にしてみると、

$("ul").append(
     $(document.createElement("li")).append('<article>俺のスタイル貫くぜ</article>')
);

うまく行かない。(cssのスタイルが適応されない!スタイル貫けや。)


ということはやっぱり、


IEhtml5要素を含む文字列をjQueryのappendしたときにcssが適応されない
のだ。

番外編として

$("ul").get(0).innerHTML='<article>俺の(ry</article>';

とか

$("ul").get(0).innerHTML='<ARTICLE>俺の(ry</ARTICLE>';

とかはちゃんとcssスタイル適応された。

※ちなみにhtml5.jsというのをつかってます。これによってIEでもhtml5要素を描画できるようになるはずなのです。

原因

この原因をさぐろーとして、jQueryの中身を見てみた。(jQuery-1.4.2)

jQueryは、jQuery.clean() というメソッドでhtml文字列をDOMに変換している。
その方法は、おおざっぱに書いちゃうとこんな感じ。

/* 実際のjQueryのソースではない!けど、ソースの4447行目ぐらいの話 */
var div = document.createElement("div");

div.innerHTML = elementString; // elementStringてのは文字列表現のhtml. "<li>aiu</li>"とか。
var elems = div.childNodes;  // このelemが変換後のDOMElementsである!

IEだと

$("ul").get(0).appendChild(elems[0]);

でうまくいかなかった。

解決策

いろいろ考えたんだけど、目から鱗的な解決策があった。

innerHTMLだとうまくいった、ということをちらりと書いたのがヒント。


ええ、答えはずばりこれ。

var el = $("ul").get(0); // 挿入したい親要素

el.innerHTML = el.innerHTML;  // 再度代入!!!!!!


こうすると、もう一回HTMLをパースしてくれるみたいで、うまくいった。
CSSスタイル適応されてない場合、
innerHTMLの再代入というTipsは一般的に使えるかもしれない。


人気者のIEだけど、まだまだみんなのサポートが必要みたい。

javascriptでrgb(r, g, b)を16進数に変換するワンライナー

こんにちは。ワンライナー好きの@m1m0r1です。
jQuerycssメソッドで色を取得したとき、rgb表示を#rrggbb形式に変換したくて困ったことはありませんか?
そんなときはこの関数を使ってみてください!

rgbTo16 = function(col){
  return "#" + col.match(/\d+/g).map(function(a){return ("0" + parseInt(a).toString(16)).slice(-2)}).join("");
}

使い方は以下のような感じです。

> alert( rgbTo16("rgb(255, 0, 255)") );
"#ff00ff"

> alert( rgbTo16("rgb(100, 240, 1)") );
"#64f001"

JavaScriptのStyleSheetオブジェクトのcssTextはReadOnly(読み込み専用)

前回の記事に関連して。

css:

/* hoge.css */
#hoge {
  width: 200px;
}

これを

<head>
<link rel="stylesheet" href="hoge.css" />
</head>

で読み込んで

JavaScript

//スタイルシートオブジェクトの取得!
var css = document.styleSheets[0];

// ルールの取得
var rules = css.cssRules || css.rules; // クロスブラウザな意味で。

rules.cssText ="#hoge {width: 20px; }"; // 値を代入

console.log(rules.cssText);

こう書いておくと、

#hoge { width: 200px; }

と表示される。

セットされてない。

element.style.cssTextはセット可能なのに。



http://help.dottoro.com/ljiiimpl.php

に、

The CSSValue.cssText and rule.cssText properties are read-only, all others are read/write.

と書いてあった。

cssに規定されていないプロパティをJavaScriptから取得できるのか

cssのルールとして規定されていないプロパティをcss内に書いたら、
それはJavaScriptからとれるんだろうか、とふと思った。

cssはこんな感じ。

/* hoge.css */
#hoge {
  width: 200px; /* 普通に指定 */
  shinout: cool; /* computedStyleにはないプロパティの指定 */
}

で、これを

<head>
<link rel="stylesheet" href="hoge.css" />
</head>

で読み込んで

JavaScriptでは

//スタイルシートオブジェクトの取得!
var css = document.styleSheets[0];

// ルールの取得
var rules = css.cssRules || css.rules; // クロスブラウザな意味で。
alert(rules[0].cssText);

こう書いておく。

すると、

#hoge { width: 200px; }

と表示される。


そりゃそうか。
shinout: cool;

という事実は見事に葬り去られた。



悲しい。




おかしいと思って


#hoge {
shinout: crazy;
}


としてみたが結果は変わらなかった。


ゴミCSSをブラウザがはじいてからDOMモデルに値を設定してるってことさ。


と、思ったがここは大人気アイドルIE先生。


IE先生でやったら、どうやら、
document.styleSheets[0].rules[0].cssTextなるものは存在しないようで、
document.styleSheets[0].rules[0].style というプロパティがあった。

これを見てみると・・・

  [width]   200px
  [shinout] cool


となっているではないか!

shinout is cool!


IEでは、意味のないCSSプロパティをとることができたぞーーー!


これができると、
css3のプロパティ名とかもhtcファイルで取得して
擬似的に再現できちゃいそうですねー!

まさにIEに一番必要な機能だわこれ!

世界一難しい数独を解くJavaScript

数学者が作った世界一難しい数独がこちらに掲載されています。
http://headlines.yahoo.co.jp/hl?a=20100824-00000018-zdn_g-ent

世界一難しい数独があるという話を聞いて、素手で解いてみました。


・・・無理です。

すべすべの壁を登れといってるようなものです。


しかし、自分にはプログラミングがある!
やつなら、なんとか解けるに違いない!

ということで書いてみました。
http://jsdo.it/shinout/sudoku/fullscreen


何をしているか、なんですが、
結局は

各マスの候補となるものを取得する
各ルール(縦、横、箱)のなかで候補の数が一つだけの数字を検出して代入
各ルール(縦、横、箱)のなかで候補の数が2、3つだけの数字を検出してヒントに使う
膠着状態になったら、2択の部分を決めちゃって、エラーが起きたらもう片方を選択。


これをやってるだけです。

2択の部分を決めちゃうのは、はっきり言ってルール違反なんですが、
さっさと答えが知りたかったんです。


論理だけで解けるというやり方があったら、教えてほしいです!

CSS3のtransformで要素のサイズを左寄せで縮める。

CSS3のtransformというのはすごく便利。

-moz-transform: scale(0.5);
-webkit-transform: scale(0.5);

これで要素が半分の大きさになります。


しかしこれだと要素が真ん中で小さくなるので、左詰めできません。



こういうときは、

-moz-transform: scale(0.5) translate(-100px, -100px);
-webkit-transform: scale(0.5) translate(-100px, -100px);

のようにすればいいんです。
これは全体の大きさが200px,200pxのときです。
中央から左詰めに移動するときの距離は50px,50pxなんですが、
translateで移動する値を指定するときは、
scaleする前の値で計算してからscale倍にして移動するようです。
注意しましょう。

pythonでジェネレータを使って順列を小さい順に出力してみる

@shinoutです。
こないだ、phperのためのGAE勉強会に行ってきて、python学んできました。
そんなわけでpythonでジェネレータを使って何か書いてみようと思い、
1-nまでの数字の順列を小さい順に出力するプログラムを書いてみました。

ええと、たとえば
3 を入れると
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
が for文で取得できるような感じです。

#-*- coding: utf-8 -*-
def order(k): 
    # 1-kまでの数字リストを小さい順に出力する。

    def orderGenerator(li):
        # 1-kまでのリストを引数にとり、それらを小さい順に出力してゆくジェネレータ
        n = len(li);
        def order0(li):
            # 再帰の初期値のための関数。
            yield li
            raise StopIteration

        def order1(li):
            # 再帰ロジック。
            defaultLi = li[:] # もともといれてくれた配列
            haveToPop = 0 # popするべきインデックス位置
            while haveToPop < n:
                li = [ defaultLi[haveToPop] ] + defaultLi[:haveToPop] + defaultLi[haveToPop+1:] 
                # ここでliは、haveToPop == 3 で[3,1,2,4]、 haveToPop == 4 で[2,1,3,4]とかになってる。
                o = orderGenerator(li[1:])
                for childLi in o:
                    li[1:] = childLi
                    yield li
                haveToPop = haveToPop+1
            raise StopIteration(li)

        return eval("order%s(li)" % min(n, 1)) # order0 か order1 を呼び出す。
    return orderGenerator(range(1,k+1))

o = order(4)
for li in o:
    print li


ジェネレータの再帰、というロジックは結構ありそうですね。