2015年7月24日に公開しました天気予報のjQueryプラグインを、タグ貼り付けだけで使えるブログパーツに拡張しました。
デザインなどのカスタマイズは従来通りに可能であり、また読み込む外部スクリプトがhttpsのため、https化したサイトにもご利用いただけます。
もちろんご利用は無料です。
(本プログラムは、Livedoor Weather HacksとGoogle Feed APIを利用していますので、これらの利用規約をご確認の上でご利用ください。)
便宜上「ブログパーツ」と紹介しておりますが、実際はHTMLタグを貼り付けるだけで利用できるクライアントサイドプログラムです。
ホームページのサイドやトップページに、天気予報を手軽に掲載したい場合に最適です。
まずはこちらの天気予報ブログパーツのページをご覧ください。
今回ご紹介している天気予報ブログパーツは、デザインをカスタマイズ可能です。デザインはCSSコード化され、ページを読み込み時に動的に設置しています。
また、共通のスタイルについても、ページ読み込み時に設置しています。
ここでは、平文のスタイルと、外部スタイルシートファイルをJavascriptで動的に設定する方法について解説します。
内容は非常にシンプルです。
まず、古いIE系用に、document.createStyleSheetが使えれば利用します。
それ以外は、直接linkタグをheadタグ内に設置します。
var path = "test.css";
if(document.createStyleSheet) {
document.createStyleSheet(path);
} else {
$("head").append("<link href=\"" + path + "\" rel=\"stylesheet\" type=\"text/css\" />");
}
var path = "test.css";
if(document.createStyleSheet) {
document.createStyleSheet(path);
} else {
var link = document.createElement("link");
link.href = path;
link.rel = "stylesheet";
link.type = "text/css";
document.getElementsByTagName("head").item(0).appendChild(link);
}
まずは準備として、スタイルを設置するためのstyleタグを設置します。
$("head").append("<style type=\"text/css\" title=\"myid\"></style>");
var style = document.createElement("style");
style.setAttribute("title", "myid");
style.type = "text/css";
document.getElementsByTagName("head").item(0).appendChild(style);
この中で、titleにmyid(任意で設定してください)を設置しているのは、この後でCSSStyleSheetオブジェクトを取得するためです。
尚、設置済みのstyleを使用することも可能ですし、予めstyleタグを設置しておいても構いません。
次に、document.styleSheetsをループして、titleがmyidに一致するものを探します。
var sheet;
for(var i = document.styleSheets.length - 1; i >= 0; i--) {
if(document.styleSheets.item(i).title == "myid") {
sheet = document.styleSheets.item(i);
break;
}
}
「判別用のmyidを設定したstyleタグを設置し、後からループでmyidがあるstyleを再取得する」というとても遠回りな処理ですが、これは取得できる要素が下記のように異なるため、必要な手順です。
オブジェクトの取得方法 | オブジェクトの種類 |
---|---|
document.getElementsByTagName("style").item(?) または $("style").eq(?)など | htmlStyleElement |
document.styleSheets.item(?) | CSSStyleSheet |
つまり、styleタグとして取得するDOMノードとは別に、CSSStyleSheetオブジェクトというものが存在しており、動的にCSSを設定する場合は後者が必要です。
ここではtitle属性を利用してhtmlStyleElementとCSSStyleSheetが一致するかを判別していますが、別の属性値を使ったり、あるいはもっとスマートなやり方があるかもしれません。ご存知の方はご教授願います。
尚、
var sheet = document.styleSheets.item(document.styleSheets.length - 1);
として「最後のCSSStyleSheetオブジェクトを取得する」のはお勧めしません。なぜなら、TwitterやFacebookのAPIや他のブログパーツなども動的にCSSを生成するため、まったく予期しないstyleを取得する可能性があるからです。
まずは、sheetにselectorとrulesを適用する関数を用意します。
var style_apply = function(selector, rules, sheet) {
if(typeof(sheet.addRule) == "function") {
var rules_arr = [];
var reg = new RegExp("([^\r\n:;]+):([^\r\n;]+?);", "g");
var matched;
while( (matched = reg.exec(rules) ) != null) {
rules_arr.push(matched[1].replace(/^ +| +$/g, "") + ":" + matched[2].replace(/^ +| +$/g, "") );
}
for(var i = 0; i < rules_arr.length; i++) {
if(!rules_arr[i]) {
continue;
}
try {
sheet.addRule(selector, rules_arr[i], 0);
} catch(e) {
//error処理
}
}
} else if(typeof(sheet.insertRule) == "function") {
try {
sheet.insertRule(selector + " { " + rules + " }", 0);
} catch(e) {
//error処理
}
}
};
処理は、旧IE系用のsheet.addRuleの利用可否で分岐しています。
sheet.addRuleの場合は、複数のルールを分離して1つずつ適用する必要があるため、正規ひょゆげんでさらに分離しています。
一方、sheet.insertRuleが使える場合は、selectorとrulesは接着してから引数に設定しています。
いずれも、念のためにtry cache(e)を利用して、エラーで処理が停止しないようにしています。
尚、ベンダープレフィックスがある場合、例えば「-webkit」付のルールをFirefoxに適用するとエラーとなります。厳密にこのエラーを回避したい場合は、rulesの解析と例外処理を追加しましょう。
後は、平文のスタイルを(セレクター) { (ルール) }のブロックごとに正規表現で分解し、上で用意したstyle_apply関数を順次適用します。
var reg = new RegExp("([^{}]+){((?:[^{}]+{[^{}]+})+|[^{}]+);?}", "g");
var matched;
while( (matched = reg.exec(conf.style) ) != null) {
style_apply(matched[1], matched[2], sheet);
}
平文のスタイルをセレクターとルールに分解し、モダンブラウザではstyle_apply関数内で再度接着してからinsertRuleしていますが、これは旧IE系でルールをさらに分解する必要があること、また正規表現によって「ついで」にセレクターとルールに分解することが可能なことから、採用している手順です。
セレクターとルールに分解しなければ、旧IE系での処理が増えますし、分解しなくても分解と同じ正規表現によるループ処理をする、という理由です。