Debug:
Array
(
[0] => 1320633953|開発日誌|静的モードでのリンク表示を変えてみる| 久しぶりのカキコ。`` 静的リンクでの挙動を変えています。URLのパスに日付情報などを含ませるように。まだ、いじっている段階なので、色々と不具合があるだろうけれど、まぁ気にしないと。`` 日付情報がある以外には、現状、PermaLink用の英数文字からなる記事タイトルを別に指定できたのですが、これはそのまま取っておくとして、そうでない場合は、記事のタイトルがそのままブラウザのアドレスバーに表示されるような感じにしてます(静的リンクが有効な場合ですが)。今時のブラウザならエンコードされた長ったらしい英数字ではなくて日本語文字列をそのまま表示してくれるので。|martin|1|1|||
[1] => 1282945798|開発日誌|記事アクセスランキングで勢いランキング| こんばんは、martinです。``ppBlogでは、アクセス解析画面に「記事アクセスランキング」が組み込まれていますが、最新版(まだ配布していませんが)ではこれに「勢いランキング 」も追加しました。` `` 従来のアクセスランキングでは、記事のレビュー数のみでの評価なので古いエントリーの記事が上位に来やすいです。これに対して、「勢いランキング」は、理論上は、一日あたりのレビュー数(平均)になるので、最近のエントリーでも上位に来ることが出来、なんとなく流行のトレンドみたいなものが見えてきて、興味深いです。`` このサイトのサイドバーのメニューに「人気記事ランキング 」があります。このリンクでも、ほぼ同じ内容のものを見ることが出来るので、興味ある方はどうぞ。タブ切り替えにしてみました。限られたスペースで、多くの情報を見せることができるので、使いどころによっては良いですね。|martin|1|1|||
[2] => 1282667147|開発日誌,JavaScript|FirefoxでのouterHTML,outerHTML-in-Firefox| innerHTML に比べると、outerHTML を使う頻度はぐっと少ない。現状、IE と Safari , Chrome , Opera が対応していて、未対応はFirefox だけ。使用頻度が低いメソッドに対して、Firefox向けに、長々しいスクリプトを書くのもどうかねぇ、と思ってググってみたところ、ナイスな投稿がありました 。``sOuterHTML = new XMLSerializer().serializeToString(oElement); `` 確かに、これは理にかなってますね。outerHTML自体は、値の取得だけでなくて、設定も出来るんだけど、そういう場面はまずないだろうから、このgetterだけで十分ですね。``<div id="Here">Hello, <strong>really strange</strong> World !</div> `対して、innerHTML なら`Hello, <strong>really strange</strong> World ! `が返されるし、outerHTML `なら、`<div id="Here">Hello, <strong>really strange</strong> World !</div> `が返される。実装例としては、``function getOuterHTML(e) {` if(e.outerHTML){ // IE, Webkit, Opera` return e.outerHTML;` } else { // Firefox (, Webkit, Opera)` return new XMLSerializer().serializeToString(e);` }`};` `あるいは、短く``function getOuterHTML(e) {` return e.outerHTML || new XMLSerializer().serializeToString(e);`};` `とか。`outerHTML
Hello, really strange World !
`
`[script]`function getOuterHTML(e) {` if(e.outerHTML){ // IE, Webkit, Opera` return e.outerHTML;` } else { // Firefox (, Webkit, Opera)` return new XMLSerializer().serializeToString(e);` }`};`[/script]`` 実際には、Firefoxだと xmlns="http://www.w3.org/1999/xhtml" という属性が付加されるので、気になるようなら適宜省けば良いでしょう。|martin|1|1|||
[3] => 1282574381|開発日誌,JavaScript|ひとつの記事に複数の拡大画像がある場合| 簡易画像ギャラリーのテスト。タイトルのような場合、ひとつの画像をクリックして、拡大表示にした際に、ポップアップした画面の右端に矢印が表示される。それをクリックすると、同じ記事に含まれる次の画像を読み込む仕様。`` 特に画像キャプションが付いている場合は、それも表示されるので、写真を主体に見せたい場合なんかには、好都合だと思います。`` ` ` ` |martin|1|1|||
[4] => 1281709863|開発日誌,JavaScript|表示オンオフ制御周りの改良| ppBlogのoParts.jsにtweenアニメーションみたいな動きを取り入れてみました。まだ試作段階ですが、テーマ:Basicであれば、左側のサイドバーの展開や、ソーシャルブックアイコンで、ちょっとした動きをみることが出来ます。`` 写真のポップアップにも。` |martin|1|1|||
[5] => 1281223799|開発日誌,JavaScript|メソッドチェーンで遅延処理をしたい,method-chain-with-delay| こんばんは、martinです。タイトル通りなんですが、要は以下のようなことを簡単に 実装したい。``foo.await (2000).say("Hello, ").await (1500).say("world !"); `` まぁfoo という関数オブジェクトがあるとして、2秒後に「Hello, 」 を出力して、そこで小休止、で1.5秒後に「world !」 を出力すると。それをメソッドチェーンに拘ってやりたい。簡単な例を挙げてみます(うまく行かないサンプルです )。``var foo = function(){}; // 関数オブジェクトを作成``foo.prototype = { // プロトタイプを設定` say : function(s){` alert(s);` return this ;` },` await : function(ms){ // ここで遅延処理をゴニョゴニョしたい` // var _this = this;` // setTimeout(function(){` // return _this; # まぁ、これはダメだけど、こんな感じでやれたらいい` // }, ms);` return this ;` }`}``var bar = new foo();`bar.await(2000).say("Hello"); // すぐに「Hello」が出力される `` メソッドチェーンを実装するとなると、return this; をかまして、用意した関数オブジェクト自身を返すようにする必要があります。上のawait関数内で、setTimeoutを用いて遅延処理をしようと思いましたが、どうもうまい方法が思いつかず、とあるサイトで質問してみました 。すると、数分後(!)に返答があって、「それ、jQueryで出来るよっ! 」と[zzz/](そのコメントは今は消されたようなんですが) まぁ確かにそうなんですが(なのであえて.delay という単語を選んだ)何かすごい技があって、それで解決!みたいなことを期待していたわけです(jQueryを使わずに)。`` 2つ目に付いたコメントで、簡単に済ませる方法はなくて、何か別のキューシステム(待ち行列システム?)を用意する必要があるよ、と。やっぱりそうか。で、沢山ヒントを頂いたんで、自分なりに作ってみました。次のようなキューシステムを用意しました。```Queue = {` entries : [], // 関数を登録する配列を用意` inprocess : null,` enqueue : function(entry){ // 関数を登録する` Queue.entries.push(entry);` },` flush : function(){ // 配列に登録された関数群を一気に実行` if(Queue.inprocess) return; // 「待ち中」なら実行しない` while (Queue.entries.length){` var entry = Queue.entries.shift(); // 配列の頭から取り出す(つまり登録順)` if(entry.toString().indexOf('await:') !== -1){ // 「待ち」のマークを見つけたら` var ms = Number(entry.split(':')[1]);` Queue.inprocess = setTimeout(function(){` Queue.inprocess = null;` Queue.flush(); // 指定時間後に処理を再開` }, ms);` return;` }` entry(); // 取り出された関数を実行` }` }`} ` こいつを最初のサンプルに適用すると以下のような感じになります。``var foo = function(){};``foo.prototype = {` say : function(s){` Queue.enqueue(function(){ // 配列に関数を登録` alert(s);` });` Queue.flush();` return this;` },` await : function(ms){` Queue.enqueue('await:' + ms); // 配列に「await:2000」みたいなマークを登録` return this;` }`} `` 自分のスキルではこの程度です[zzz/] キューシステムに頼らずに自己完結できる目から鱗な手法がないですかねぇ。``とりあえず動作サンプルを以下に。ボタンを押すと、``var bar = new foo();` bar.await(1500).say('Hello, ').await(2000).say('world!'); `ってのが実行されます。ここでは、ボタンを押して1.5秒後に「Hello, 」、更に2秒後に「world !」とボタンの右側に表示されます。```遅延実行 `
` 何か、「こうしたらいいよ」とかのアドバイスあればよろしくお願いします。`[script]`var foo = function(){};`foo.prototype = {` say : function(s){` Queue.enqueue(function(){` o("#H").html(s, 'add');` });` Queue.flush();` return this;` },` await : function(ms){` Queue.enqueue('await:' + ms);` return this;` }`}``Queue = {` entries : [],` inprocess : null,` enqueue : function(entry){` Queue.entries.push(entry);` },` flush : function(){` if(Queue.inprocess) return;` while (Queue.entries.length){` var entry = Queue.entries.shift();` if(entry.toString().indexOf('await:') !== -1){` var ms = Number(entry.split(':')[1]);` Queue.inprocess = setTimeout(function(){` Queue.inprocess = null;` Queue.flush();` }, ms);` return;` }` entry();` }` }`}``function sayHello(){` var bar = new foo();`bar.await(1500).say('Hello, ').await(2000).say('world!');`}`[/script]|martin|1|1|||
[6] => 1280546339|開発日誌,JavaScript|IE8でのHTML5要素有効化あれこれ,various-HTML5-enabling-scripts| もう7月も終わりですね、martinです。相変わらず時の流れは速いもので。`` このサイトのブログの基本テーマ(スキン)「Basic」では、試験的にHTML5 を導入しています。HTML5では新しい要素がいくつか追加 されていますが、IE9 未満のブラウザでは、article やheader , nav などのクールで新しい要素に対するスタイルシート指定が効かない、という事が昔から知られています。これに対するアプローチとして、 document.createElement を使うとスタイルシートでの指定が可能になるよ、というのがよく知られています。初出は Sjoerd Visscher さんあたりでしょうかねぇ。`document.createElement(”article”); // 未知の要素articleに対してIEでもCSS指定が可能になる `` このdocument.createElementを使うテクニックは、いろんなところで見かけることができて、有名どころでは、Remy sharp氏のhtml5.js あたりですね。`` もっとも、このテクニックを使っただけでは、IEでHTML5化を効かせたページを印刷したときまでは反映されないので、これに対しては、IE Print Protector がよく知られていると思います(個人的には、印刷のサポートまではあまり興味がありませんが )。`` で、このcreateElementを使うテクニックは、ベタに書けば以下のような感じになります。``// ここでは簡潔化のため、以下の6個の新要素に絞ってます。`<!--[if lt IE 9]>`var html5_elements = ["header", "nav", "article", "section", "aside", "footer"]; `for (var i = 0, len = html5_elements.length; i < len; i++){` document.createElement(html5_elements[i]); // 各要素に適用`}`<![endif]--> `` どこで最初に見かけたのか失念しましたが、これを一行(ワンライナー)で簡潔に済ませたスクリプトを見たときはいたく感心しました。Dean Edwards氏のブログ もこうなっています。`"header,nav,article,section,aside,footer".replace(/¥w+/g, function(a){document.createElement(a)}); ` 上のポイントは、replaceメソッドの引数に関数を指定できて、その関数内では、正規表現にマッチした要素を適宜適用していく点です。ループみたいなことを勝手にやってくれる点ですね。おそらくこれ以上短くは書けないのではないかと思うのですが、息抜きに自分なりにいくつか考えてみました。`"header,nav,article,section,aside,footer".split(',').sort(function(a){return document.createElement(a)*1}); ` これも、似たような発想からですね。自動でなんかやってくれるという。`with("header,nav,article,section,aside,footer".split(',')))while(length)document.createElement(pop()); ` ここではwith 構文を使ってみました。これもなかなかシンプルです。同じくwithと、Enumerator を使って、`with(new Enumerator("header,nav,article,section,aside,footer".split(',')))for(;!atEnd();moveNext())document.createElement(item()); ` これは、ちょっと長いし、Enumerator Object はマイナーですかね。`` 短さ命で、グローバル変数の汚染なんて気にしないぜっ、という向きには以下のようなものもありかと思います。``s="header,nav,article,section,aside,footer".split(',');while(s[0])document.createElement(s.pop()); `` for 文関連では、``for(i in s="header,nav,article,section,aside,footer".split(','))document.createElement(s[i]); `とか`for(i=0;n="header,nav,article,section,aside,footer".split(',')[i++];document.createElement(n)); `とかですかねぇ。`` ちなみに、配列を作るのに、文字列にsplit() をかませるというのは、よく見かける手法です。ここでの、6個ぐらいの要素数ではあまり差は出ませんが、要素数が増えてくると、逐一ダブルクォート(or シングルクォート)で括っていくやり方と大きく差が付いてきます。``var html5_elements = ["header", "nav", "article", "section", "aside", "footer"]; // これより`var html5_elements = "header,nav,article,section,aside,footer".split(','); // こっちが記述が短い `` 正規表現から配列も出来ますね。``var html5_elements = "header,nav,article,section,aside,footer".match(/¥w+/g); `` 以上、トリビアルなエントリーでした[署名/]|martin|1|1|||
[7] => 1280233709|開発日誌,JavaScript|HTML5 FileAPIの不満な点,inflexible-HTML5-File-API| こんにちは、martinです。なかなかまとまった時間が取れないので、ppBlogの最新版をリリースできずにいます[zzz/]`` 最新版のバージョンとしては、v1.9.0 を予定しています。新機能としては、コメント認証機能 だとか、HTML5を意識したppBlogエンジンでしょうか(ちなみにテーマBasicのソースはHTML5仕様ですよ)。`` で、このHTML5 なんですが。過去のエントリーでいくつかあるように、最新版では、記事投稿の際に複数ファイルアップロードが可能になっています。HTML5のFileAPI を積極的に採り入れたものにしようか、それとも「レガシーな」もので実現させるか迷いましたが、とりあえず「レガシー」なバージョンで行こうと思います。理由はいくつかありますが、一番の理由は、どうもHTML5のFileAPIの使い勝手が悪い点です。`` ブログでの写真投稿において、一度に複数枚の写真を選択してアップロードできる点は、HTML5を使う魅力のひとつですが、この「複数枚のファイルを選択 」というのが、どうも洗練されていない印象です。例えば、アップする写真を複数枚決めてそれをアップロードする場合を考えてみます。頭の中では、大まかに写真をのせる順番が決まっていて、ファイル選択画面から、コントールキー(CTRL )を押しながら、順序良く写真をいくつか選んだとします。最新のブラウザなら以下のように、multiple を指定するだけで、この複数枚選択という動作が可能になります。``<input type="file" name="src[]" multiple /> ``でも、残念なことに、この選んだ順序 というのは、FileList には反映されない のです。否応なしに、ファイル選択画面上で表示されている通りの順序になるようです。何か、選んだ順序を紐付けするような属性が欲しくなります。`` もうひとつ 。選んだ複数枚のファイルは、FileList配列に収められて、あたかも配列のようにDOM操作が可能ですが、この配列は、readonly 、つまり読み取り専用 のようです。たとえば、ちょっと余分に画像を選んじゃったよ、という場合に、その余分なファイルだけをリストから除きたいというケースは、間違いなく出てくると思いますが、そういう操作は出来ないようです。再度、すべてのファイルを選び直す必要があります。これは、ユーザーには使い勝手が悪いですね。`` というわけで、上記の理由により、ppBlogではW3C FileAPI の積極的な採用は見送りました。でも、HTML5に頼らずとも、一度に複数枚のファイルのアップロードは可能です。Stickman さんが、2005年に、すでにそういうギミックを見付けていました 。最初見たときは、目から鱗でした。やってることはすごくシンプルなんですが、まさにコロンブスの卵ですね。で、彼のスクリプトは、ppBlogにはちょっと冗長でしたので、参考にしつつ、ppBlog仕様にしました。実際のデモを見てみましょう。尚、デモでは「アップロード」ボタンは、文字通りただのボタンなので、実際にはファイルはアップロードされませんが、雰囲気は十分に伝わると思います。`` レガシーな複数ファイルアップロードのデモ →http://p2b.jp/demo/EasyFileUpload.html
`` また、Firefox最新版など、File APIに十分対応しているブラウザでは、選んだ画像をサムネイル表示するようにしています。Firefoxだと以下のようなスクリーンショットです。Firefox以外では、普通に選んだ画像のファイル名が選んだ順にリスト表示されます。`` ``この部分のスクリプトは以下の感じ。`` if(window.File && window.FileList && window.FileReader){ // FileAPIに対応しているなら` var file = el.files[0];` if(file.type.match(/image.*/)){` var reader = new FileReader(); // FileReader オブジェクト!` reader.onload = function(){` var span = d.createElement("span");` span.innerHTML = '<img class="thumb" src="' + this.result + '" alt="preview" /> (' + Math.round(file.size / 1000) + ' KB)';` li.insertBefore(span, li.lastChild);` };` reader.readAsDataURL(file); // 画像データの読み込み` }` } `` レガシーなインターフェイスですが、任意のリストを削除出来ますし、HTML5仕様より却って高機能(=使い勝手が良い)な気がします。`` ちなみに、デモのソースを見ていただけると分かりますが、INPUT[type=file] 要素に、レガシーにonchange イベントハンドラを仕込んでいます。document.addEventListerで監視しても良いのですが、IEでは、onchangeイベントがバブルしないようで[うーむ/]`` 余談ですが、「目から鱗」の語源は、新約聖書の「使徒行伝(しとぎょうでん)」中のエピソード、見えなくなっていたパウロ (サウロ)の目からうろこのようなもの(コンタクトレンズ?)が外れて再度見えるようになったという「パウロの回心」からですね。「豚に真珠」と同様、日本とか中国由来と思いきや、新約聖書からの諺です。
|martin|1|1|||
[8] => 1276620033|開発日誌,PHP|短縮URLの元を知る その2,rollout-shorten-url-part2| こんにちは。前回のエントリーのコメントで「生ログ」の「リンク元」にも「expand」アイコンをとの要望がありましたので、そうしました。ついでに、短縮URLのサービスホストを判定するロジックの精度を少しばかり高めました。単に、文字列の長さのみで判定すると、p2b (笑)だとか、twitter とかも短縮URLサイトと判定してしまうので。`` 具体的には、ホワイトリストのホスト名を配列で指定するようにして、そうでなければ「expand」アイコンを付けるという感じです。現状、以下のようになっていますが、適宜追加しても良いでしょう。``$not_shortening_hosts = array('twitter', 'www', 'p2b'); `` これは、view.phpの78行目で指定しています。`` ブラックリスト方式でやろうとすると、どうやら100以上のサイト を指定する必要がありそうで、ちょっとシャレになりません。`` 最新版を添付しておきます。`[file:1276620033_view.php:45.6/]|martin|1|1|||
[9] => 1276572292|開発日誌,PHP|短縮URLの元を知る| おはようございます、martinです。WC、初戦勝ちましたねぇ。正直期待していなかっただけに喜びも倍増といったところ。決勝トーナメント進出!なんて日が来るのでしょうか。`` さて、今回は前回のアクセス解析の続きみたいなものです。前回のエントリーで、短縮URLの元を知るサイトとして、http://knowurl.com/を紹介しましたが、他にもいくつかありますね。LongURL なんかもそうです。LongURL は、Firefoxの拡張版 もあるようですね。API も公開されているようでjQueryのプラグインとかもあるようです。APIがあるんで、ppBlogでも使える様なJavaScriptを書いても良いですが、仕組みは結構単純なので、外部のAPIに頼らずともppBlogのみで完結できそうです。`` まずは、短縮URLがどのような仕組みになっているのか知る必要があります。短縮URLを提供しているサイトはいくつもあります(現時点で動いているのは bit.ly、j.mp、cli.gs、Short.ie、Idek.net、is.gd、sn.im、u.nu あたり)が、これら殆どのサイトでやっていることはリダイレクト です。PHPを使えば、その辺りの情報は簡単に取得出来ます。例えば、http://bit.ly/aKhZ1Gは、http://p2b.jp/201006-get-html5-fileuploading-moduleというリンクの短縮形ですが、PHP経由でアクセスしてみると、リダイレクト先の情報などが入手出来ます。PHP5 であれば、get_headers() 関数が使えます。便利ですね。この関数を使って以下を実行すると、``<?php`$url = 'http://bit.ly/aKhZ1G';`print_r(get_headers($url, 1));`?> `大まかには、以下のようになります。``Array(` [0] => HTTP/1.1 301 Moved /* Permanentlyと続くこともある */` [Location] => http://p2b.jp/201006-get-html5-fileuploading-module /* リダイレクト先がある! */` [MIME-Version] => 1.0` [Content-Length] => 313` [X-Powered-By] => PHP/5.1.6`) `[Location] の項目に短縮URLの元リンクが収められていますね。なので、配列からこれを取り出せばOKです。じゃPHP5 ではないサーバーではどうするか。fsockopen()関数 を使います。以下のような記述で行けるでしょう。``$url = 'http://bit.ly/aKhZ1G';`$_url = parse_url($url);`$port = isset($_url['port']) ? $_url['port'] : 80;`$host = isset($_url['host']) ? $_url['host'] : '';`$path = (isset($_url['path']) ? $_url['path'] : '/').(isset($_url['query']) ? '?'.$_url['query'] : '');`$request = "GET ".$path." HTTP/1.1¥r¥n";`$request .= "Host: ".$host."¥r¥n";`$request .= "Connection: Close¥r¥n¥r¥n";``if($fp = fsockopen($host, $port, $errno, $errstr, $timeout=3)){` stream_set_timeout($fp, 3);` $ret = '';` fputs($fp, $request);` do {` $ret .= fgets ($fp, 4096);` } while (strpos($ret, "¥r¥n¥r¥n") === FALSE); // ヘッダー部分で十分` fclose($fp);`} ```これを実行すると、以下のような感じになります。``HTTP/1.1 301 Moved`Server: xxxx/0.7.42`Date: Tue, 15 Jun 2010 02:46:59 GMT`Content-Type: text/html; charset=utf-8`Connection: close`Set-Cookie:xxxx`Location: http://p2b.jp/201006-get-html5-fileuploading-module /* これが欲しい */`MIME-Version: 1.0`Content-Length: 313 ``これから、Location: の部分を取り出す正規表現は、以下のような感じでしょうか。``$redirectURL = preg_replace('{^.+?Location:¥s([^¥n]+?)¥n.+$}s', '$1', $ret); `これで、$redirectURL にhttp://p2b.jp/201006-get-html5-fileuploading-moduleという文字列が入ることになります。`` 以上のことをやると、リダイレクト先が分かるのでppBlogのアクセス解析に組み込んでみました。「リンク元 」の項目で、短縮URLっぽいものには、下のショットにあるように「expand 」というアイコンみたいなやつが付くようになります。`` `` そしてこれをクリックすると、Ajax経由で情報をゲットして以下のような表示に変わります。`` `` リダイレクト先があれば、これがその場で表示されます。これはリンクになっていますが、そのサイトへのリンクではなくて 、グーグルでそのリンクを調べるようになっています。それで怪しげなサイトであればブラウザでアクセスするのを避けることが出来るわけです。`` ちなみに、Ajax部分は、以下のような関数で実現しています。思ったよりシンプルに出来ました[にこっ/]``` var expand = function(url){` var target = o(oParts.evt.target);` var loader = oParts.create('IMG').src('../Images/loader.gif'); /* ローディングアニメーション */` target.addAfter(loader);` oParts.server.get('view.php?expand=' + url, function(ret){ /* これがAjax部分 */` loader.away();` if(ret == url){` target.css('color:gray; cursor: default').html('redirect 0').title('リダイレクトはありません').on('click', function(){});` } else {` target.css('color:crimson; border-color: green').html('Redirect: <span onclick="googleIt(¥''+ret+'¥')" title="グーグルで検索">' + ret + '</span>');` }` });` } ```` 一応、これを実現するためのview.php を添付しておきます。stat ディレクトリの既存のやつと置き換えればOKかと思います。前回添付したものの上位版になります。`` 今週末にppBlogの最新版配布を予定していますが、これはそのバージョンに組み込み予定です。|martin|1|1|||
[10] => 1275370140|開発日誌,PHP|HTML5によるファイルアップロードスクリプトの配布,get-html5-fileuploading-module| おはようございます、martinです。前々回ぐらいに、HTML5を用いたプログレスバー付きのファイルアップロードのデモを示しました。この手のスクリプトは、プログレスバーの表示にFlashやJavaを用いていることが多いのですが、ファイルサイズが大きくなる傾向になったり、設置がややこしかったりします。`` 何件かソース希望のリクエストがあったので、ppBlogからのスピンアウトとして配布しようと思います。配布するやつは、PHPとJavaScript(+CSS)だけでプログレスバーを実現していて、設置も比較的簡単ではないでしょうか。添付ファイルを展開すると以下のファイルが含まれています。`` ` index.html(ここにアクセス) ` fileUpload.php(PHPでのファイルアップロード処理用) ` oParts.js(プログレスバーのためのJSライブラリ) ` progressbar.png(プログレスバーの画像) ` PIX(アップロードした画像を保存するフォルダ) ` `` 基本的には、展開したフォルダを然るべき場所にまるごとアップロードして、index.htmlにアクセスすればOKかなと思います。サーバーによっては、PIXディレクトリのパーミッションの指定が必要かもしれません(707とか)。`` 画像を保存するディレクトリは、PIXにしていますが、これは適当に名前を変えても良いでしょう。fileUpload.phpの最初の方で指定出来ます。``$pix_dir = 'PIX/'; // 画像を保存するディレクトリ。パーミッションは707とか。 `` うまく動けば、アップロード中は以下のような画面になっているかと思います。`` ``*あくまでサンプルです。最低限の実装なので、セキュリティ関連は、各自でいじって下さい。JavaScriptをいじれば、プログレスバーに加えて、全体の何パーセントが完了みたいなことも出来るでしょう。`[file:1275370140_MultipleFileUpload.zip:12.7/]|martin|1|1|||
[11] => 1272557652|開発日誌,PHP|HTML5による複数ファイルアップロード,multiple-file-upload-by-HTML5| こんばんは、martinです。以前、Flex(Flash)を用いた複数ファイルのアップローダー を紹介しましたが、実はHTML5 だけで出来るのになぁ、と思っていました。現時点で、IE8を除く主要なブラウザでは軒並み、HTML5のINPUT要素に対するmultiple 属性に対応しているので、それによる実装をppBlogに施してみました。複数ファイルを選択可能にするには、input要素にmultipleを指定するだけです。``<input type="file" name="src[]" id="src" multiple /> `` とりあえず実装してみただけですが、きちんと動作しました(ここのエントリー は画像を複数枚一度にアップロードした)。UI をどうするかで試行錯誤しましたが、プロトタイプにしてはまぁまぁかなと思っています。`` `` さて、複数の(画像)ファイルがアップロード出来るようになると、アップロードする枚数に応じて、サーバーにデータを渡す間、じっと待たされるようになります。現状、HTML5 のみではぼーっと待つしかありません[すやすや/] なので、アップロードの進捗状況を示すプログレスバー が欲しくなります。この手のスクリプトはウェブ上にいろいろありますが、どれもFlashを用いたり、Perl(+JavaScript)を用いたりしたものです。出来ればPHP(+JavaScript)のみで完結させたい。`` いろいろ調べてみると、PHPとJavaScriptのみでは、ファイルアップロードに伴なうプログレスバーのギミックを提供するのは無理という記述ばかりです。というのもPHPには、ファイルアップロードの途中経過を知らせる仕組みが備わっていないからです。実は、PHP5.2 以上であれば、PECL APC拡張機能を組み込んで可能 なのですが、サーバー側で PECL APCエクステンションをインストールする必要があり、これはレンタルザーバー等では敷居が高いでしょう。`` なので(Perlはあまり好きになれないという理由もあり )PHPとJavaScriptのみによる実装を考えてみました。まずは、PHPにおける、POST メソッドによるファイルアップロード時の挙動を知る必要があります。マニュアルによれば、基本的に以下の手順を踏みます。`` サーバー上に転送される(画像)データは、最初は一時的なディレクトリ(テンポラリディレクトリ)にアップロードされます。この一時的なディレクトリは、だいたい/tmp ディレクトリのことが多いです。php.iniで指定可。 ` 画像データの転送が無事に終わると、move_uploaded_file 関数を用いて指定したディレクトリに画像データを移動させます。 ` `` PHPでのネックは、この1番目の進捗状況を知るメソッドが備わっていないことです(なのでこの部分だけはPerlで処理するスクリプトがある)。サーバーサイドで提供しないのであれば、こちらからゲットしに行きましょう。アップロード中のデータは、テンポラリディレクトリに溜まっていくので、そのディレクトリのサイズは徐々に大きくなるはずです。なので、そのディレクトリのサイズを定期的に監視すればOKということになります。この「定期的に監視 」という部分にJavaScriptのAjax を使えば良いわけです。`` ディレクトリのサイズは、以下の記述で取得可能です。`$tmp_dir = '/tmp'; // 取得したいテンポラリディレクトリ``$size = 0; // ディレクトリのサイズ``$d = opendir($tmp_dir);`while($file = readdir ($d)){` if(is_file($tmp_dir.'/'.$file)){` $size += filesize($tmp_dir.'/'.$file);` }`}`closedir($d);`echo($size); // ディレクトリの合計サイズを得る` `` なお、上の例では、テンポラリディレクトリは/tmp ですが、これを取得したい場合は、ファイルアップロード時に現れる変数の$_FILES['src']['tmp_name'] を利用して、``dirname($_FILES['src']['tmp_name']); ``で取得可能です。`` あとは、AjaxとPHPで、このディレクトリサイズを返すような記述をして、それをJavaScript側に渡し、プログレスバーっぽく見せればOKとなります。具体的なデモ を見てみましょう。うまく行けば、転送中のブラウザ画面は下のようなスクリーンショットになります。Firefox3.6.3 やSafari , Google Chrome の最新版で動くと思います。`` |martin|1|1|||
[12] => 1269996654|開発日誌,JavaScript|IE9ではDOMContentLoaded をサポートするようだ,IE9-supports-DOMContentLoaded| こんにちは、martinです。久しぶりの書き庫な気がします。`` IE9のプラットフォームプレビュー が出ていたんで、インストールしてみました。最初に試したことは、他の主要なブラウザでは実装済みのDOMContentLoaded がサポートされているかなぁ、ということでした。現時点では、まだでしたが、IEBlog によると今後のロードマップに、DOMContentLoadedのサポートがあるようです。DOMContentLoaded自体は、DOM Level 3 Eventsには定義されていないので、IE9が標準仕様に忠実であろうとするならば実装は微妙だなぁ、と思っていたんですが、HTML5には定義されています (注意: リンク先はかなりページが重い )ね。`` IE9でDOMContentLoadedがサポートされるのはまことに喜ばしいことですが、IE9が普及するのはまだまだずっと先の話でしょう。なので現状では、IE向けにはDOMContentLoaded相当の機能を自前で実装する必要があります。世の中には、jQueryを始めとした便利なJavaScriptライブラリーがいくつかありますが、猫も杓子もDiego Perini氏が発見したdoScrollメソッドを使う手法 に則っています。ppBlogでのoParts.js でも、doScrollの実行をもって、DOMパース完了とみなすやり方で実装しています。`` さて、このdoScrollメソッドですが、MSDNの説明にあるように、`` The doScroll method is available on all objects, regardless of whether they support scrollbars.
` 引用元: doScroll Method (A, ABBR, ACRONYM, ...) ` `` ほぼすべての要素について適応可能です。多くのJavaScriptライブラリーでは、``document.documentElement.doScroll('left'); `` というふうに、document.documentElementに適用しているケースが殆どですが、何でも良いので、以下のようなやつもOKです。```(function(){` if(navigator.userAgent.match(/MSIE/)){ // IEなら` try {` new Image().doScroll() ; // new Imageオブジェクトについて適用` onReadyFunc(); // DOM構築後に最初に呼び出す関数` } catch(e){ setTimeout(arguments.callee, 1);}` } else { // IE以外` document.addEventListener("DOMContentLoaded", onReadyFunc, false); // DOM Level 3 Events相当` }`})(); `` 別にnew Imageオブジェクトをdocument.body にappendChild する必要もありませんし、メモリーリークも起こしません。以下のようにコメント文を生成するメソッドcreateComment()を用いても良いでしょう。これも、既存の文書に作ったコメントをappendする必要はなく、ただ宣言するだけで動きます。```(function(){` if(navigator.userAgent.match(/MSIE/)){ // IEなら` try {` document.createComment().doScroll() ; // document.createCommentについて適用` onReadyFunc(); // DOM構築後に最初に呼び出す関数` } catch(e){ setTimeout(arguments.callee, 1);}` } else { // IE以外` document.addEventListener("DOMContentLoaded", onReadyFunc, false); // DOM Level 3 Events相当` }`})(); `` doScroll()の引数は省略可能です。省略するとscrollbarDown が適用されるので、document.documentElement.doScroll()だと、実際に画面がスクロールしてしまうかもしれません(なのでたいてい”left” を指定している)。new ImageやcreateCommentだと、DOMツリーに追加するわけではないので引数は省略して構いません。`` new Image().doScroll()なんて、短い記述で済むんでいいなぁ、と思うけれど。[署名/]|martin|1|1|||
[13] => 1261627359|開発日誌,JavaScript|CSS3のtransformをIE8でも使いたい,CSS3-Transform-for-IE8| こんばんは、martinです。Firefox やWebKit系のSafari 、グーグルのChrome などは、CSS3 の魅力的な機能を色々取り入れています。中でも、CSS3のtransform やドロップシャドウ系は、ブログで写真を見せる場合などに凝った演出が出来るので、仕様が正式に決まるのが待ち遠しいですね(そう言えば、ボックスのドロップシャドウ box-shadow ですが、CSS3の勧告候補から消えた のかなぁ)。便利な仕様だとは思うのですが。`` ちなみに、transform とは「変形」のことで、CSSのみで画像やらボックスやらを自在に回転させたり、ゆがませたりできる優れものです。で、例によってIE系はCSS3の対応は遅れています。とは言っても(これまたいつものように)transformに関しては、IEは実にIE5.5 の時から似たようなものを実装していました ! なので、それらを駆使すれば、CSS3相当のtransformが実装できそうです。`` transformが使えると何がうれしいって、例えば以下のようなポラロイド写真みたいなギャラリーがCSSのみで簡単に出来ます。実は下のショットはIE8 でのものです。` `` 画像の回転に関して、FirefoxやWebKit系は、画像の中心を回転軸として回転させます(なので回転軸は移動しない)。これは直感的で分かりやすいです。これに対して、IEは回転軸が指定した回転角度によって刻々と移動します。なので、標準仕様に似せようと思うと、回転軸を動かさない様にするための補正計算が必要になります。この計算にちょっとてこずりましたが、何とか回転軸が動かないような補正をすることが出来ました。`` `` で、とりあえずモノになりそうなものが出来たのでデモサイトを挙げておきます。画像へのマウスオーバーで拡大なんてのもCSSのみで出来るのですが、それもIEで動くようにしています。`` →「CSS3 Transformを使ったギャラリー(IE互換) 」
` FirefoxやSafariでは、完全にCSS3のみで実現していて、IEでは、IE特有のフィルター機能をJavaScirptを通して操作しています。ボックス要素のドロップシャドウについては、以前、まぁまぁ凝ったスクリプトを書きました が、新たに要素を追加しないといけないなど、あまり納得のいくものではありませんでした。今回ドロップシャドウに関しては、あまり凝ることはせずに、IEのフィルター機能を素直にそのまま使っています。``progid:DXImageTransform.Microsoft.dropshadow(enable=true,OffX=3, OffY=7, Color='#11000000 ', Positive='true'); `` 実は最近知ったのですが、フィルターのColor には通常のRGB 形式だけでなく、透明度も指定できる#AARRGGBB の形式が使えるので、黒色の透明度を高くすればより影っぽくなります。CSS3レベルのぼやけた感じまでは出ませんが、まぁ、これで良しとしましょう。`` 使い方は、簡単で、形はHTCファイルですが、JavaScriptの外部ファイルとして動作するようにしてます。これは、以前のドロップシャドウのスクリプトと同じです。それをIEのみが解釈する条件コメントの中に書いています。`<!--[if IE]>` <script type="text/javascript" src="js/css3transform.htc"></script>`<![endif]--> `` これを書いておくだけで、スタイルシートに記された`` -moz-transform: rotate(-2deg);` -webkit-transform: rotate(-2deg);` transform: rotate(-2deg); `などを解釈して、IEのフィルター機能(Matrix Filter)で同等のことを表現します。デモページにあるように、IEでもCSS3のtransformはおよそ実現できるみたいです(まぁ、そもそもがIEのMatrix仕様を参考に実装したのでしょうけど)。`` このスクリプトを添付しておきます。`[file:1261627359_css3transform.htc:4.6/]|martin|1|1|||
[14] => 1261614576|開発日誌|タグモード表示の改善| こんばんは。コメントで、タグエントリーを総表示するときの仕様についてアドバイスがあり、確かにそうだなと思ったので。現状では、タグモードのとき(このサイトに表示されているタグのアイコンをクリックした時)、下のショットのように、縦にリスト表示されます。` ` これは、アーカイブ表示に準じてそうしたのですが数が増えてくると縦表示は見辛いですね。もっとも、スタイルシートの制御で横に並べることは出来ますが、タグクラウドの特徴のひとつである「エントリー数に応じて文字の大きさを制御する 」というところまではしていませんで(PHPプログラムのmodules/tags.inc.php の方で)。`` なので、modules/tags.inc.php をタグクラウド表示に見合うように修正しました。適切にスタイルシートを設定すると以下のような表示になります。このショットはこのサイトでの例なのですが、タグ数が少ないのであまり雲っ て感じではないんですが、増えてくると見栄えも違ってくるでしょう。これよりもうちょいタグ数が多い、個人ブログの方はこんな感じ です。` `` ちなみに、テーマ「ベーシック」での、この部分の表示は以下のようにしています。参考になれば。クラス名などは従来通りです。``/*---------------------------[ タグ 一覧表示用 ]----------------------*/`div.tags-list {` width: 450px;` margin: 30px auto;` background: url(Images/clouds96.png) right top no-repeat;`}`div.tags-list ul {` list-style: none;` margin-top: 60px;`}`div.tags-list ul li{` margin: 0 6px 3px 6px;` white-space: nowrap; /* 日本語ワードの改行を適切にするための指定 */` display: inline;` text-align: center;` zoom: 1;`}`div.tags-list h3 {` margin: 2em auto;` color: navy;`} `` これに対応したmodules/tags.inc.php を添付しておきます。`` あ、追記ですが、この添付ファイルの最初の方に、``$minFontSize = 13; // 最小文字サイズ(ピクセル)`$maxFontSize = 36; // 最大文字サイズ(ピクセル) ``という2行があります。これはタグ表示の文字サイズを制御するためのものです。エントリー数に応じて、タグの文字が大きくなっていきますが、際限なく大きくなっても困るので、上限を設けています。ピクセル指定です。適宜、調整して下さい。`[file:1261614576_tags.inc.php:2.2/]|martin|1|1|||
[15] => 1261140380|開発日誌|テーマのプレビューで編集位置まで戻す| タイトルだけだと何のことやら分からないと思いますが、ppBlogの「テーマ管理」では、テンプレートのHTMLやスタイルシートを修正した際に、どういう風に変更が反映されるか、実際にプレビューボタンで確認することが出来ます。そのプレビュー画面では、以下のように「戻る」のリンクでもとの編集画面に戻ります。` ` 従来だと、この戻るリンクで戻ると、マウスのカーソルは長々しいテキストエリアの先頭に戻っているので、再度編集部位を探しつつ、そこまでスクロールする必要がありました(Ctrl +F で検索するのが常套手段ですが)。スタイルシートの編集では、テキスト量が多い傾向にあり、直前の編集部位を探し出すのは大変です。`` なのでその辺を改善してみました。やりたいのは以下のことです。` `` テキストエリアのスクロールバーの位置はJavaScriptから制御することが出来ます。具体的には、scrollTop を使います。流れとしては、プレビューボタンを押したタイミングで、スクロール量を取得(scrollTopで可能)、プレビューから戻ったときに、取得した値を指定すれば良いわけです(指定もscrollTopです)。実際には、テキストエリアだけではなく、ブラウザのスクロールバーもscrollTopで制御できるので、この2つのスクロール量を保持するようにしています。`` やってみると意外と簡単に実装できました。もっと早くやっておけば良かったです。試されたい方は、以下のutils.php とmodules/theme.inc.php でどうぞ。`[file:1261137079_utils.php:97.4/]`[file:1261137079_theme.inc.php:20.3/]|martin|1|1|||
[16] => 1260999974|開発日誌,JavaScript|localStorageでIE8がクラッシュする件 続き,localStorage-crashes-IE8-with-empty-value-part2| こんばんは。前回の書き庫 で、localStorageに空の値を入れるとIE8 がクラッシュすると書きました。なので、空の値が入らないようなチェックを入れれば良いのですが、それだけだとナンなので、症状をもう少し追ってみました。`` もう一度、(IE8が)クラッシュするコードを書いておきます。``function addItem(){` var key = document.getElementById("key").value;` var value = document.getElementById("value").value;` window.localStorage[key] = value; // valueが空白だとクラッシュ!`} `` 以下のように、直接空の値を入れる分には大丈夫でした。``function addItem(){` var key = document.getElementById("key").value;` var value = document.getElementById("value").value; // これは使用しない` window.localStorage[key] = ""; // 直接、空の値を入れる → これは大丈夫。`} `` ほうほう。で、クラッシュするデモページのHTMLソースをよく見てみると、input[type=text] でvalueの値を指定していないですね。もしかしてこのせいかなぁ、と``<input type="text" id="value" value="" /> ``value="" を追加しましたが、やっぱりクラッシュします。input[type=text] の値がないときでも、 document.getElementById("value").value はちゃんと文字列として解釈されます(typeof value == "string" )。デモページは、input[type=text] のvalue値を取得していますが、これはTEXTAREA 要素であっても、やはり内容が空っぽの場合、IE8ではクラッシュを引き起こしました。`` 何でですかねぇ。試しに、強引に文字列ではないオブジェクトを入れてもクラッシュしません 。``window.localStorage[key] = document.getElementById("value"); // これは [object] という文字列に変換される `` 確かに、文字列のstringだとブラウザが解釈しているのに、それが空っぽだとクラッシュするわけです。じゃ、以下はどうだろうか。```var empty = ""; // 空っぽの変数を用意する。`window.localStorage[key] = empty; // これはセーフ。クラッシュしない。 ``さすがにこれはオッケーです。じゃ以下はどうだろうか?`` var val = document.getElementById("val").value; // これが空っぽとする` var empty = ""; // val もempty も空っぽの場合` alert(empty === val); // 厳密等価演算子は true を返す` window.localStorage[key] = val; // なのに、val だとクラッシュ! `` とりあえず string と認識しているはずなのに、代入する段階以降で、別のクラッシュを引き起こす「何か」と解釈されるらしい。というわけで、とりあえず以下のようにすれば、IE8でのクラッシュを回避できることが分かった。でも、ナンだかすっきりしないですね[うーむ/]```function addItem(){` var _key = document.getElementById("key").value;` var _val = document.getElementById("val").value;` window.localStorage[_key] = new String(_val); // new String()で明示してあげる` alert("localStorage."+_key+" の値は「"+localStorage[_key]+"」です。");`} ``new String() でちゃんと文字列オブジェクトとして再評価 してあげると良いらしい。というわけで、IE8でもクラッシュしないlocalStorageのデモページをリンクしておきます。`` →http://p2b.jp/demo/localStorage2.html`` ちなみに、上のコードでalert(typeof new String(_val)) は何となるでしょうか? これは、 もはやstring ではなくobject となります。文字列オブジェクトです。|martin|1|1|||
[17] => 1260967011|開発日誌,JavaScript|localStorageで空の値を入れるとIE8がクラッシュする件| こんにちは。そろそろppBlogにも[g]localStorage[/g]に対応したスクリプトを組み込もうかと思っていますが、IE8で空(から)の値を入れるとブラウザがクラッシュして終了する現象に遭いました。MacBook Pro上のVMware Fusionに入れたWindows7 RC版IE8で発生します。正規版だとOKなのかなぁ。`` 簡単なデモを用意しました(IE8 ならクラッシュしても良い状態でアクセス )。→http://p2b.jp/demo/localStorage.html`` Firefox3.5では値が空でもエラーも何も起きませんが、IE8では即座にクラッシュです。そのスクリーンショットをば。適当なキーを設定して(例えば「foo 」)、値を何も設定せずに「追加」ボタンを押すと発生。`` ``上記ページのスクリプトはごくシンプルなもの。```if(typeof localStorage != "object"){` if(typeof globalStorage == "object"){ // Firefox2 possible` localStorage = globalStorage[location.hostname];` } else alert("お使いのブラウザはこのスクリプトに対応していません。");`}``function addItem(){` var key = document.getElementById("key").value;` var value = document.getElementById("value").value;` window.localStorage[key] = value;`} `` 空の値かどうかチェックすれば済む話ですが。`` 関連エントリー(解決編?) `` ■http://p2b.jp/200912-localStorage-crashes-IE8-with-empty-value-part2|martin|1|1|||
[18] => 1260213051|開発日誌,PHP|Flexを用いた複数ファイルアップロード,Flex-FileUploadApp| こんばんは、martinです。前回のエントリーで述べていたように、次期バージョン(v1.9.0 )では、画像ファイルのアップロードの際に、複数の画像をまとめてアップロードできる仕組みを提供予定です。`` 現状では、複数の画像を一度にアップロードするには、FlashかJavaを使うしかありません。JavaもFlashも素人ですが、とっつきやすいのはFlashですし、ファイルアップロードに関しては、色んなサイトでソースコード付きのFlash/Flexのデモサイトがあったので、Flexを用いたインターフェイスを作ってみました。``→実際に試すことが出来るデモサイト
`` 実際には、Coding Cowboys というサイトにあったプログラムをベースに、好みのインターフェイスになるよういじっただけです。`` `` ローカルのフォルダからは基本的に任意のファイルを選べるのですが、画像ファイル(*.jpg , *.png , *.gif )のみに絞っています。また、Flexの練習もかねて、デモページのFlashではアップロードした画像を見ることが出来るように、右下に画像ギャラリーへのリンクボタンを付けてます。``→画像ギャラリーへのリンク
`` ちなみに、このリンク先の画像ギャラリーは、Flashとは関係なしに、単にPHPでページを生成しています。CSSのみを用いたシンプルなものです。IE向けのハックは使ってませんが、IE6でもそう表示が崩れることはないかなと期待。アップロードされた画像ファイルの内、最新のJPEG画像 を5枚表示するようにしてます。`` `` 今後、いじるとすれば、ファイルサイズ上限を指定したりとかですかね。とりあえず。|martin|1|1|||
[19] => 1259112153|開発日誌|アクセス解析に記事アクセスランキングを統合| こんばんは。先週、A型インフルエンザのワクチンを接種しました。ラボのみんなが行く際に「マーチンも行く?」「うん。」で。3-4日ほど痛かったなぁ。`` さて、v1.8.8 のリリースに向けて、アクセス解析をいじってます。現行の最新版(v1.8.7)では、記事のアクセスランキングを記録する機能がついていますが、タイミングによっては集計されたランキングがリセットされる現象もあるようで、その辺りはバックアップファイルを作るようにしたりして、せっかくの集計がリセットされないような手段を講じています。`` で、前々から記事のアクセスランキングは、アクセス解析でも見られるようにするのが良いなと思っていたんで、そうしてみました。`` `` それ以外にも、見栄えの修正やら、動作を少し変えたりしています。例えば、「検索ワード」などにおいて、データ量が多いと表示するテーブルが縦長になり、ページスクロールするのにもたつきを感じるようになります(少なくとも、MacBookProユニボディーの中のVMwareで動いているWindows7ではそうです)。なので、こういうのは、テーブル要素を含んでいるDIV要素の下端をブラウザの下端ぐらいまでにとどめて、DIV要素にスクロールバーが表示されるようにしています。これで、動作もスムーズにまりました。上のスクリーンショットでも、スクロールバーがDIV要素に表示されているのを確認できると思います。`` ある程度以上のバージョン(v1.6 以上ぐらい?)であれば、記事アクセスランキングの集計がなくても問題なく動くと思うので、先に試されたい方はどうぞ。フィードバックなど大歓迎です。基本的には、stat ディレクトリのview.php とstat.css の上書きです。後、ランキング表示用のアイコンが2つです。これはstat/icon ディレクトリにアップロードします。`[file:1259112153_stat188.zip:14/]|martin|1|1|||
[20] => 1258656418|開発日誌,JavaScript|カラーキーワードをHEXやRGBに変換したい,ColorKeyword-to-Hex-or-RGB| こんばんは。久しぶりにDean Edwards のブログを覗いたら、MSIE でカラーキーワード(red とかtomato とか)やらをHEX 方式(#f01234 とか)に変換するやり方が載ってました。``function toHex(color) {` var body = createPopup().document.body,` range = body.createTextRange();` body.style.color = color;` var value = range.queryCommandValue("ForeColor");` value = ((value & 0x0000ff) << 16) | (value & 0x00ff00) | ((value & 0xff0000) >>> 16);` value = value.toString(16);` return "#000000".slice(0, 7 - value.length) + value;`}; `へぇ。これにも元ネタがあって、それはerik's weblogのコメント です。`` ppBlogには、cornerplay.js というJavaScriptがあって、指定ボックスの角を丸くしたり凸凹にしたりできる動作を担当しています。具体的には以下のような感じです。`` こんな感じで、コーナーをちょいと変えると、見た目のアクセントになります。
`` で、このボックスの背景色に、tomato とかindigo とかlavender などのいわゆるカラーキーワード でも指定できるように、これらカラーキーワードをHEX方式に直した対応表も含めているんですよね(147色ぐらいある )。今、考えるとほかにもやりようがある気もしますが、当時は仕方ないなぁとその対応表をJSON配列にして含めてました。`` このDean Edwardsのやり方なら、対応表なんていりませんね。記述が短くなってファイルサイズも小さくなるだろうし言うことないです。ただ、これはIE限定なので、Firefoxやその他のブラウザでも動くように改良してみましょう。Deanは、「ほかのブラウザは、getComputedStyle()が使えるからバッチリだぜ。」って述べています。`` 調べたところ、各ブラウザ(Firefox、Opera、Chrome・SafariなどのWebKit系)で結構動作が違っていて興味深かったです。ただ色の変換をしたいだけなのに、わざわざ既存のDOM構造に影響を与えるようなやり方(色を取得したいがために、document.createElement で新たに要素を作成して、それをdocument.body.appendChild してDOM構造を改変した後で、getComputedStyle() にて色を取得)は、reflowの問題 もあり出来れば避けたいところ。`` 大体以下のような感じでいけそうです。``function ColorToHEX(color){` var d = document, ecolor, element = d.createElement("button");` element.style.color = color;` ecolor = element.style.color; // ポイント!` if(ecolor.indexOf("#") !== -1) return ecolor; // Operaの可能性が高い` if(d.uniqueID){ // IE向け` color = element.createTextRange().queryCommandValue("ForeColor");` color = ((color & 0x0000ff) << 16) | (color & 0x00ff00) | ((color & 0xff0000) >>> 16);` return "#" + ("000000" + color.toString(16)).slice(-6);` } else { // IE以外のブラウザ` if(/webkit/i.test(navigator.userAgent)){ // Google Chrome, Safariで基本カラーなら` var basicColors = {` "aqua" : "#00ffff", "black" : "#000000", "blue" : "#0000ff", "fuchsia" : "#ff00ff", "gray" : "#808080", "green" : "#008000",` "grey" : "#808080", "lime" : "#00ff00", "maroon" : "#800000", "navy" : "#000080", "olive" : "#808000", "orange" : "#ffa500",` "purple" : "#800080", "red" : "#ff0000", "silver" : "#c0c0c0", "teal" : "#008080", "white" : "#ffffff", "yellow" : "#ffff00"` }` for (var col in basicColors){` if(color.toLowerCase() === col) return basicColors[col];` }` }` if(ecolor.indexOf("rgb") !== -1){ // RGB形式で色を返した!` color = ecolor;` } else color = getComputedStyle(element, null).getPropertyValue("color");` return "#" + color.replace(/rgb¥((¥d+?),¥s*(¥d+?),¥s*(¥d+?)¥)/g, function(a, r, g, b){` return ("000000" + ((+r) * 65536 + (+g) * 256 + (+b)).toString(16)).slice(-6);` });` }`}; `` 流れとしてはこうです。`` IEでcreateTextRange()を使うのでBUTTON要素を作成。 ` それに色を指定する。element.style.color = color ` 指定した色の取得。この時点で、OperaがHEX形式の値を返してくれる。Opera一抜け。 ` 同様に、この時点で、IEはqueryCommandValue経由でBGR値を取得できるので、それをHEXに変換。 ` IE以外でFirefoxは、ecolor は指定したままの値。getComputedStyleを使うとRGB値を返してくれる。 ` WebKit系は振る舞いがややこしい。 Webの基本17色、例えばred の場合、 ecolor = element.style.color にはredがそのまま入り、tomato などの拡張色ならRGB形式を返す。じゃ、getComputedStyleはどうかというと、まだDOMに組み入れていないので 空の値を返す。 ` なので、WebKit系で基本17色であれば、それはJSON対応させてHEX値を返すようにします。そうでなければ、RGB値を返してくれるのでHEX値に変換。 ` 以上。document.body.appendChildなどでのDOM改変は必要ない点がポイントです。 ` `` WebKit系の振る舞いが独特で、特別な処理が必要になりますが、いずれにせよ、DOMの改変を伴わなくて良いかなぁと(まぁcreateElementはしますが)。ちなみに、OperaでもgetComputedStyle は使えますが、FirefoxやWebKitがRGB値を返すのに対して、OperaはHEX値を返します。RGB値からのHEX値への変換は、いくつか方法があるでしょう。上では正規表現を用いています。逆にHEXからRGBへの変換も色々あると思います。```function HEXToRGB(hex){` return hex.replace(/#?(¥w{2})(¥w{2})(¥w{2})/, function(a, r, g, b){ ` return "rgb(" + parseInt(r, 16) + ", " + parseInt(g, 16) + ", " + parseInt(b, 16) + ")"}` );`} ``や``function HEXToRGB(hex){` var color = parseInt(hex.replace("#", ""), 16);` return "rgb(" + ((color >> 16) & 0xff) + ", " + ((color >> 8) & 0xff) + ", " + (color & 0xff) + ")";`} ``などですかね。`` ついでなので、カラーキーワードからRGB値に変換する関数も挙げておきます。考え方は基本的に同じです。DOMの改変は必要ないです。```function ColorToRGB(color){` var d = document, ecolor, element = d.createElement("button");` element.style.color = color;` element.style.display = "none";` ecolor = element.style.color;` if(ecolor.indexOf("rgb") !== -1) return ecolor; // WebKit系が一抜けする可能性あり。` if(ecolor.indexOf("#") !== -1){ // OperaはHEX値を返す` return ecolor.replace(/#?(¥w{2})(¥w{2})(¥w{2})/, function(a, r, g, b){ ` return "rgb(" + parseInt(r, 16) + ", " + parseInt(g, 16) + ", " + parseInt(b, 16) + ")"}` );` }` if(/webkit/i.test(navigator.userAgent)){ // WebKit系で、基本カラーの場合はRGB値を返さない` var basicColors = {` "aqua" : "rgb(0, 255, 255)", "black" : "rgb(0, 0, 0)", "blue" : "rgb(0, 0, 255)", "fuchsia" : "rgb(255, 0, 255)",` "gray" : "rgb(128, 128, 128)", "green" : "rgb(0, 128, 0)", "grey" : "rgb(128, 128, 128)", "lime" : "rgb(0, 255, 0)",` "maroon" : "rgb(128, 0, 0)", "navy" : "rgb(0, 0, 128)", "olive" : "rgb(128, 128, 0)", "orange" : "rgb(255, 165, 0)",` "purple" : "rgb(128, 0, 128)", "red" : "rgb(255, 0, 0)", "silver" : "rgb(192, 192, 192)",` "teal" : "rgb(0, 128, 128)", "white" : "rgb(255, 255, 255)", "yellow" : "rgb(255, 255, 0)"` }` for (var col in basicColors){` if(color.toLowerCase() === col) return basicColors[col];` }` }` if(d.uniqueID){ // IE用` color = element.createTextRange().queryCommandValue("ForeColor");` return "rgb(" + (color & 0xff) + ", " + ((color >> 8) & 0xff) + ", " + ((color >> 16) & 0xff) + ")";` } else { // FirefoxはこれでRGB値を返す` return getComputedStyle(element, null).getPropertyValue("color");` }`} ``` こんな感じですかねぇ。ファイルサイズが小さくなるなら、cornerplay.jsを書き換えても良いなぁ。`` ちなみに、圧縮したら920バイトになりました。```function ColorToHEX(b){var g=document,a,e=g.createElement("button");e.style.color=b;a=e.style.color;if(a.indexOf("#")!==-1){return a}if(g.uniqueID){b=e.createTextRange().queryCommandValue("ForeColor");b=((b&255)<<16)|(b&65280)|((b&16711680)>>>16);return"#"+("000000"+b.toString(16)).slice(-6)}else{if(/webkit/i.test(navigator.userAgent)){var f={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",grey:"#808080",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",orange:"#ffa500",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00"};for(var c in f){if(b.toLowerCase()===c){return f[c]}}}if(a.indexOf("rgb")!==-1){b=a}else{b=getComputedStyle(e,null).getPropertyValue("color")}return"#"+b.replace(/rgb¥((¥d+?),¥s*(¥d+?),¥s*(¥d+?)¥)/g,function(h,j,i,d){return("000000"+((+j)*65536+(+i)*256+(+d)).toString(16)).slice(-6)})}};`
|martin|1|1|||
[21] => 1257509401|開発日誌,PHP|アクセス解析でドメイン毎にソート| こんにちは、martinです。もう師走はすぐそこですね。先日[w]レヴィ・ストロース[/w]氏が亡くなりました。何となく今年だろうなぁと思って、日記の方で新年の抱負 を語っていたんですが、ちっとも進んでいません[zzz/]`` フォーラムでアクセス解析関連のバグの報告がありました。→http://forum.p2b.jp/index.php?mode=box&UID=4592`` ホストごとの集計の際に、ピリオドで区切られた長いホスト名を短くする処理を入れていたんですが、ホスト名が取得できずにIPアドレスが登録されているときにも、これを適用してしまいIPアドレスが削られて表示されていました。なので正規表現部分を修正しました。`` これだけだと、1行だけの修正なんで、ついでにドメインごとの集計もする記述を加えました。` `` どういうドメインでソートするかは、374行目で指定しています。`` $sort_type = array('.jp', '.com', '.net', 'ne.jp', 'co.jp'); ``なので、例えば、or.jp やad.jp なんかも追加したいということであれば、` $sort_type = array('.jp', '.com', '.net', 'ne.jp', 'co.jp', 'ad.jp', 'or.jp'); `みたいにすればOKです。自動的に認識されるかと思います。`` ファイルを添付しておきます。stat ディレクトリのものと入れ替えてください。`[file:1257509401_view.php:38.7/]|martin|1|1|||
[22] => 1256678778|開発日誌|16色のカラーパレット|こんばんは。`コメントで、ppBlogのエディタのカラーパレットが、色が豊富すぎるのでは?というご指摘があり、確かにそう思っていました。計算上は、1677万色程度の指定が可能ですので。`` ブログの文章で、そこまでの色数が必要かというとそうではないでしょうね。なので、基本となる16色のみに絞ったバージョンも用意してみました。スクリーンショットを挙げておきます。`` `` これを有効にするには、editor.jsの6行目にある変数を有効にします。``var useBasicColor = true; // これで簡易パレットになる `` false (あるいは0 )を指定すれば、従来のカラーパレットです。`` ちなみに、簡易パレットの色は、editor.jsの593行目で指定しています。``var cols = '', bcolors = ['red','blue','yellow','black','green','silver','lime','gray','olive','white','maroon','navy','purple','teal','fuchsia','aqua']; `` お好みの順番や色に変えても良いでしょう。`` 試されたい方はどうぞ。何か不具合を見つけましたらお知らせください。```[file:1256678778_editor.js:39.6/]|martin|1|1|||
[23] => 1253331309|開発日誌,JavaScript|IEでCSS3のドロップシャドウを使いたい,IE-CSS3-Dropshadow| こんばんは、martinです。CSS3+JavsScriptネタでも。目標は、IEでもCSS3のドロップシャドウ効果が得られるようになること。以下のような感じで、Firefoxとほぼ同等の効果を得ることが出来ます。左がIE8で右がFirefoxです。``[2010/08/04 01:02:25] プログラムアップデート→http://p2b.jp/201008-IE-compatible-CSS3-dropShadow
`` `` CSS3 では、テキストにドロップシャドウの効果を付けるtext-shadow が定義されていて (まだドラフト段階かな)、既にFirefox3.5やSafari, Chrome, Opera10などは対応しています。典型的には、以下のような感じで指定します。``text-shadow: 1px 2px 3px tomato; // 順にx-offset、y-offset、ぼかし半径、影の色。最初に色指定でもOK。` `` また、テキストに対する影だけでなく、DIV などのボックス要素に対するドロップシャドウとして、box-shadow というのもあり、これは、FirefoxとSafari、Chromeで先行実装されています(Opera10はまだかな)。指定の仕方は、text-shadowと同様です。ほんとは、spread-radius というオプションのパラメータもあるのですが、これはなくても良いんじゃないかと思ってます。``` -moz-box-shadow: 1px 2px 3px chocolate; // 順にx-offset、y-offset、ぼかし半径、影の色。`-webkit-box-shadow: 1px 2px 3px chocolate; // Safari, Chrome用の記述。` `` また、box-shadow固有の属性として、inset というのがあります。これは、ドロップシャドウをボックスの内側に見せるものです。``` -moz-box-shadow: inset 0 0 1em red;`-webkit-box-shadow: inset 0 0 1em red;` `` 今のところ、insetオプションを理解するのは、Firefox3.5だけのようです。`` あれっ、ドロップシャドウって、IEが10年ぐらい前から実装してなかったっけ?と思う方もいるでしょう。そう確かにそんなものがありました。IE独自のフィルター機能を使ってそれっぽいことが出来ます。``` これらが紹介された当初はクールだと思いましたが、使い勝手が今イチだったのと、あとは、玉に瑕というか白璧の微瑕(はくへきのびか)だったと思うのは(ここまでいうと誉めすぎですが)、影の「ぼかし 」が指定出来なかったことです。キリッとした輪郭の影では折角の魅力も半減です(個人的に)。おそらく、影のぼかしはそれなりにCPUのパワーを必要とするので、当時はまだ難しかったのかもしれません。なので、これらが広くWebサイトで使われるということはなかったです。AjaxのようにまたしてもIEの早すぎた実装だったわけです。`` 昨今、パソコンの性能も上がり、IE以外のモダンなブラウザがCSS3のtext-shadow をサポートするようになったせいか、この頃は色んなサイトでドロップシャドウ効果を見かけるようになりました。`` なので、まだまだシェアの大きいIEでも、CSS3に準拠した、それらしいドロップシャドウを付けたいということで考えてみました。基本的な考え方は、上で述べたマイクロソフト独自のFilter Blur を用いて、影のぼかしを演出するということです。このBlurは、要素自体をぶれた 表現にするので、それを別のレイヤーとして生成して、それを影を付けたい要素の背後に配置するというものです。別のレイヤー生成というと、大げさな気もしますが、ぼやけた感じを出すには、これ以外の方法はない気がしますし、Firefoxにしても、影は別レイヤーなんじゃないんでしょうか、知りませんが。`` とりあえず、それっぽいモノができたのでデモをお見せします。`` IEでもCSS3のドロップシャドウを実現するデモ
`` text-shadow もbox-shadow もカンマで区切った複数の指定が可能なので、これにも対応してみました。``.multi-text-shadow {` font: bold 3em Arial, sans-serif; color: white;` padding: 10px;` text-shadow: 1px 2px 2px #555, 0 0 1em blue, 0 0 0.2em blue; /* ここでは3つ指定している */`} `` 上の指定だと、以下のような感じになります。` ` また、現時点では、Firefox3.5のみが対応しているinsetオプションも解するようにしてみました。IE8でのスクリーンショットをば。`` `` で、実際の設置方法ですが、なるべく簡単に設置できるように、外部スクリプトとしました。CSSでの記述は、特別なものは必要ないです。普通に上に挙げたような感じで、text-shadowやbox-shadowの指定をしておけば良いです。後は、ドロップシャドウを効かせたいページで、外部スクリプトを次のように呼び出せばOKです。`<script type="text/javascript" src="path/to/css3shadow.htc "></script> ` ファイルの名前css3shadow.htc さえ変えなければOKで、それを置いた相対パスを、各自で記述すれば良いです。`` これ以外の指定方法としては、このスクリプト自体は、完全にIE向けなので、Firefoxその他のブラウザには不要なものです。なので、その分のトラフィックを減らしたいということであれば、IE向けの条件コメントを使って、``<!--[if lt IE9]>`<script type="text/javascript" src="path/to/css3shadow.htc"></script>`<![endif]--> ``でも良いと思います。これであれば、Firefoxなどではコメントとして解釈されるので、サーバーからcss3shadow.htcが呼び込まれることはないです。`` まだ、書き上げたばかりなんで、細かいチェックは出来ていませんが、外部スクリプトを呼び込むだけなので、気軽に試して頂けるかと思います。css3shadow.htc を添付しておきます。8KB未満の小さいファイルです。`` ちなみに、影の色指定ですが、透明度を設定できるrgba 方式にも対応しています。これは、通常のRGB形式に加えて、4つめに透明度を指定出来るものです。ゼロで透明、1で不透明となります。```rgba(123, 100, 125, 0.3); /* 透明度30%の指定 */ `` オフトピですが、RGBって、たまにRBGとタイプミスしたり、あれっ?どっちだっけと混乱するときがありますが、キーボードで、上から順にRGBとなっている 、と覚えると良いです。`` 以下、Mozillaの参考サイトを挙げておきます。````[file:1253331309_css3shadow.htc:7.7/]|martin|1|1|||
[24] => 1253028569|開発日誌,PHP|縮小時に写真のクオリティを保持させたい,JPEG-Quality| こんにちは。この頃のエントリーは、アップデート情報ばかりなので、たまには別の話題でも。コメントで画質のことに触れられていたので。`` ppBlogでは、ひとつの記事にいくらでも画像を貼り付けることが出来ます。その際に、サイズの大きな画像(デジカメで撮った写真など)は、アップロード時のオプション指定にもよりますが、そのままの大きさでアップロードして保存された後(これはPIX ディレクトリへ)、この大きさでは表示するのに大きすぎる場合には、予め指定された大きさ(初期値は350ピクセル)に縮小され、これはPIX/s2 ディレクトリへ保存されます。`` 記事中に表示されるデジカメの写真などは、最初はこのPIX/s2 ディレクトリにある縮小された写真が表示されている場合が多いかと思います。そして、それをクリックすると、PIX ディレクトリにある元の大きさの画像を表示するという流れになっています。`` 一昔前は、(コンパクト)デジカメの写真一枚のファイルサイズは、せいぜい1MB(メガバイト)程度だったんですが、この頃は、画素数の増大に伴い、3-4MBを超えることも珍しくありません。ppBlogでは、3-4MB程度のファイルサイズでもアップロード可能な処置を入れていますが、これを頻発させるとサーバーに負担をかけうるので、予めお使いのパソコンで写真のファイルサイズを小さくしてアップロードすべきでしょう。個人的には、フリーのソフトである「縮小専用。 」を使っています。一括処理も出来て重宝しています。Vistaであれば、標準でついているWindowsフォトギャラリーにある「修正」で、適当に修正を施した後、それを閉じれば自動的に修正されたもので上書き保存されますが、これでもそれなりにファイルサイズが小さくなります(縦横サイズはそのままで、例えば3.49MBが1.2MBになったりとか。まぁ、これでもまだアップロードするには大きいんですが)。`` さて、ここからが本題ですが、もともとファイルサイズが大きい写真をリサイズなどをしてファイルサイズを落とすと、当然ながら写真のクオリティーは低下します。更に、それをppBlogを介してサーバーにアップロードすると、そこで更にリサイズされて、画質が低下することになります。気になる方には気になる部分でしょう。`` ppBlogでは、画像のリサイズは、utils_admin.php にあるcreate_thumbnail() 関数(462行目あたり)が担っています。その中に、`` case 2 : ImageJPEG($img_out, $output); break; ``という行(500行目あたり)がありますが、これはJPEG画像を出力する関数です。実は、この関数の第三引数(ひきすう)に、出力する画像の品質を指定できます。`` quality はオプションであり、0(品質は最低 ですが、ファイルはより小さい)から100(品質は最高ですが、ファイルは 最大)の範囲で指定します。デフォルトは IJG 品質値(75)です。
` 引用元: PHP: imagejpeg - Manual ` `` 現状、ppBlogでは、この部分の指定はしていないので、初期値である75 というクオリティーで保存されていることになります。じゃ、他の値ではどうなるのかな?という疑問が出てきます。なので、簡単に調べてみました。Vistaに初めから付いているサンプルピクチャー(「フランジパニのクローズアップ。」by Kevin Forest氏)を元画像として、Qualityオプションを小さい方から順に10, 30, 75, 80, 85, 90, 100 と指定していって、それぞれの画像を保存、そのままのファイルサイズでアップロードしたのが以下です。`` まずは元の画像です。350ピクセルにリサイズされていて(品質75)、クリックするとオリジナルのサイズで表示されます。`` `` 以下、色んな品質でリサイズしていった画像を載せます。低い品質から。`` ` ` ` ` ` ` `` これから言えることは、JPEGの性質上、元の写真による部分もあると思うけれど、デフォルト値の75では、ノイズが少し目立ち、品質85だと明らかな改善が見られる。ファイルサイズは、15.6KBが20.4KBと約1.3倍。品質90-100は、見た目のクオリティーはほぼ変わらないにも拘わらず、品質100でのファイルサイズ増大が顕著(90で25.2KBなのが100だと70.9KB。ちなみにオリジナルは105KB)。`` なので、結論としては、初期値の75 での品質が気になる方は、85-90 あたりの値を指定すると、リサイズしても満足した画質が得られるんじゃないでしょうか。たった一枚のサンプル画像からの帰結ではあるけれど、まぁ妥当なところであると思います。`` というわけで縮小された写真の画質が気になる方は、utils_admin.php の500行目あたりを、`` case 2 : ImageJPEG($img_out, $output, 85); break; // あるいは90 ``としてみては如何でしょうか。`` 将来的には、画像アップロード時に、指定できるようにしても良いですね。|martin|1|1|||
[25] => 1250901310|開発日誌,PHP|記事アクセスランキング修正版| こんばんは。数個前の記事で紹介した記事アクセスランキングですが、個別記事にアクセスした際には、表示されていませんでした。これは、$RANKING という変数のグローバル宣言をしていない ためという凡ミスでした。。なので、それを修正したutils.php を添付しておきます。また、現状では、「最近のエントリー」で表示される記事数(つまり定数RECENT_ENTRIES の同じ数がリスト表示されますが、showRanking関数のこの部分を好きな数字に変えることでリストの表示数をコントロール出来ます。`` 尚、別件ですが、はてなのブックマークエントリー数を取得するAPIが変更になった ようで、現状ではPHPのエラーが出るかと思います。これは、ソーシャルブックマークのアイコン表示を有効にしている場合です。これの対策としては、utils.phpに記述してある$SBM_LIST 変数内を修正する必要があります。具体的には、この中の'はてなブックマーク'の部分、``'b.hatena.ne.jp/entry/json/?url=' `を`'api.b.st-hatena.com/entry.count?url=' `に書き換えます。|martin|1|1|||
[26] => 1250867875|開発日誌,JavaScript|Google AJAX Feed APIを利用したスライドショー,Google-AJAX-Feed-API-Slideshow| こんばんは。前回の書き庫コメントでアップロードした画像のスライドショーの話が出ていたので。`` ブログのサイドバーでスライドショーを見せるブログパーツは結構あると思いますが、良く見かけるのはAdobeのFlashを用いて表示させる方法。これは純粋にJavaScriptを使うよりは、凝った演出が出来る傾向にあります。もっとも、最近はモダンなブラウザでは[g]Canvas要素[/g]をサポートしているので、JavaScriptだけでも凝った演出が可能になってますけど(ppBlogでは、写真を回転させたりして表示できますが、この部分でCanvasを使っています)。`` 単なる好みの問題ですが、サイドバーでスライドショーを見せる際に演出に凝りまくるのは、あまり好きでありません(特にFlash系)。なので、スライドショーを見せるにしてもJavaScriptのみで動くシンプルなものが良いなぁ、と思いました。スクリプトは自前で用意したいところですが、画像切り替えのアルゴリズムなどを考えるとはまりそうなので、ここは既知のJavaScriptライブラリーを使うことにします。`` で、Google AJAX API が良さそうでしたので、これを使ってスライドショーを付けてみました。Googleで、スライドショーそのもののスクリプトを公開している ので、それを利用するだけです。実際のデモは、http://p2b.jp/demo/slideshow.html あるいは http://martin.p2b.jp/index.phpで確認出来ます(3paneのテーマであれば右側に表示される)で確認できます。`` 早速ですが、簡単な設置手順を記しておきます。``` mediaRSSファイルが必要なので、それを作成するadmin.php とmodules/mrss2.inc.php をゲット。 ` 管理画面の「各種ツール」に「MRSSの作成 2」というメニューがあるので、それを選択。これでmediaRSSが作成される。 ` 表示させたいテーマのtemplate.phpに必要なJavaScript関連の記述をする。 ` `` 基本的にはこれで足ります。template.phpに記述するJavaScriptですが、先に挙げた小生のサイトでは、まず以下のようにして動作に必要なファイルをGoogleのサーバーから外部スクリプトとして呼び込んでいます。`` <script type="text/javascript" src="http://www.google.com/jsapi?key=(AJAX APIのキー) "></script>` <script src="http://www.google.com/uds/solutions/slideshow/gfslideshow.js" type="text/javascript"></script> ``AJAX APIのキー指定ですが、これはなくても動きますが、グーグルのサイトで簡単に入手出来る ので手に入れておくと良いでしょう。`` この2つのスクリプトを通じて、予め用意したmediaRSSファイルを読み込んで、画像を順次表示させていく訳ですが、mediaRSSファイルを手書きで用意するのは大変なので、こういうものはppBlogに作らせましょう(手順1, 2)。ppBlogで生成されるmediaRSSは、具体的にはhttp://martin.p2b.jp/feeds/mrss.xmlのような感じになります。`` このmediaRSSファイル読み込み時に起動する呼び出し関数は、以下のような記述です。グーグルのサイトにあるサンプルコードとほぼ同じです。```function load(){ // mediaRSSファイルを読み込んだ際のコールバック関数` var src = "http://martin.p2b.jp/feeds/mrss.xml"; // 読み込むRSSファイルを指定` var options = {` displayTime: 3000, // 一枚あたりの画像表示時間(ミリ秒)` transistionTime: 1000, // 画像切り替えのフェードアウト・フェードインの時間(ミリ秒)` scaleImages : true, // 指定したサイズに合わせて画像を縮小させるかどうかのオプション指定` linkTarget : google.feeds.LINK_TARGET_BLANK // 画像をクリックした際に新しいウィンドウ(タブ)でリンク先を開くか` };` new GFslideShow(src, "slideframe", options); // slideframeというID名を持つ要素に対して発動` }` google.load("feeds", "1");` google.setOnLoadCallback(load); ``これに対するHTMLの記述は以下のような感じです。これもtemplate.php内の記載になります。``` <div id="slideshow" style="margin: 60px auto 30px auto; width: 120px; height: 150px; background: url(theme/3pane/Images/slide-frame.jpg) no-repeat; padding-top: 30px;">` <div id="slideframe " style="width: 100px; height: 100px; margin: auto; position: relative;"></div>` </div><!--#slideshow--> ``ここでは、インライン形式のスタイルシート指定にしていますが、勿論スタイルシートのCSSファイルで指定しても構いません。設置の参考にするには、上に挙げたデモサイトが分かりやすいかと思います。`` 尚、このスライドショーは、マウスが画像に載ると、そこで一時停止します(これはデフォルトの動作)。で、そのままクリックするとその画像が含まれる記事にリンクするようになっています(これはmediaRSSの内容による)。`` ppBlogに組み込めるように、admin.phpとmodules/mrss2.inc.phpを添付しておきますね。`` 参考リンク: http://www.google.com/uds/solutions/slideshow/reference.html``[file:1250867875_admin.php:28.6/]``[file:1250867875_mrss2.inc.php:2.5/]|martin|1|1|||
[27] => 1250286945|開発日誌,PHP|作成ページでPHPが通るようにしたい| こんばんは。昨日に引き続き。`` ppBlogでは、ブログのエントリーとは別に自由にページを作成することが出来るので、いわば[g]CMS[/g]のような使い方も可能です。このページ作成機能ですが、以前から改善したいなぁと思っていたことがありました。それは、作成したページの中に記述したPHPがスクリプトとしてちゃんと動作する ということです。`` 現状では、例えば、以下のような記述をしてページを作成してもそのまま書いた文字列が出力されてしまいます。``<?php` echo "Bonjour à tous!"; // やぁ、みんな!`?> ``上の記述は、以下のようになる。``echo "Bonjour à tous!"; // やぁ、みんな!`?> `` ページ作成画面でPHPスクリプトを自由に記述できれば、PHPに慣れた方なら色んなことが出来るようになります。なので、そうできるようにしてみましょう。ppBlogでは、作ったページは、単なるテキストファイルとして、pages ディレクトリに保存され、それをmodules/pages.inc.php を介して、HTMLとして出力されます。なので、pages.inc.phpモジュールをいじります。具体的には、このファイルの中で定義されているoutputPage() 関数に手を加えれば良いです。`` 流れとしては、テキストファイル中に書かれてあるPHPタグ<?php・・・?> があれば、その中身をeval 関数で評価、その結果を保持しておく。eval関数はその場ですぐに評価されるため、それがHTMLとして出力されるのを防ぐために、出力のバッファリングを有効にしておく、ということです。簡単に実装出来そうですね。以下のような記述でいけるかと思います。``if(preg_match_all('{<¥?php(.+?)¥?>}s', $page, $mt)){ // PHPタグを含むなら` $BUFF = array(); // 評価した結果を保存する入れ物を用意しておく` ob_start(); // 出力のバッファリングを有効に` $length = count($mt[0]);` for($i = 0; $i < $length; $i++){` $php = $mt[1][$i]; // 実行させたいPHPスクリプトの中身` if(eval($php) === FALSE){ // PHPのパースエラーなら` $BUFF[] = "ppBlog warning: parse error!";` } else $BUFF[] = ob_get_contents(); // きちんと評価されれば、その結果を取得` }` ob_end_clean();` } `` ポイントは、ob_start関数とeval関数の組み合わせです。その際に、eval関数の返り値は、パースエラーならFALSEを返すけど、きちんと評価されれば、ob_get_contents関数で補足可能ということですかね。`` 実際には、これ以外の微調整が必要ですが、それも反映させたPHP記述が有効になるpages.inc.php を添付しておきます。既存のやつを上書きして問題ないです。`` と、これを書いている途中で思いついたのですが、ppBlogでは、[style]...[/style] の形式で、その記事だけに適用させるスタイルシートを指定出来ますが、これもページ作成画面でも指定出来るようにしました。このサイトで「人気記事ランキング」というページを作りましたが、そのソースは以下のようになってます。これをそのままページ作成画面のテキストエリアに貼り付ければOKです。```<h2>人気記事ランキング</h2>`<?php`echo '<ol>'.NL;`echo showRanking(); // utils.phpで定義している独自の関数も使える!`echo '</ol>'.NL;`?>``[style]`h2 { color: slateblue; margin: 1em auto 2em auto; }`ol li span {` background: pink; font: bold 12px Arial; color: navy; padding: 2px 3px;`}`ol {` list-style-type: decimal;` width: 480px; margin: auto;`}`[/style] `` コメントにもありますが、utils.php で定義している関数も使えるので色々と応用が利きそうです。ちなみに、上のスタイルシートの指定で、実際には以下のように、div.page-box が自動的に付加された形で出力されます。`` <style type="text/css">` div.page-box h2 { color: slateblue; margin: 1em auto 2em auto; }` div.page-box ol li span {` background: pink; font: bold 12px Arial; color: navy; padding: 2px 3px;` }` div.page-box ol {` list-style-type: decimal;` width: 480px; margin: auto;` }` </style> `` スタイルシート指定も有効するには、utils.php もちょいと書き換えが必要です。これも添付しておきます。最近のバージョン(1.7-1.8)であれば、既存のを上書きしても特に動作に問題はないかと思います(いつでも元に戻せるように元のutils.phpのバックアップはとっておいて下さい )。|martin|1|1|||
[28] => 1250196829|開発日誌,PHP|各記事の閲覧数ランキングを表示させたい| こんばんは、久しぶりにmartinです。`` フォーラムの方で、「記事の表示回数と順位の表示は出来ないでしょうか? 」というエントリーがあって、ちょっとプログラミングがしたくなったのでとりあえず書いてみました。このサイトで、テーマをBasicにすれば、左側のサイドバーに「人気エントリー」というのが表示されていると思います。`` 基本的には、utils.php をいじることで実現できます。utils.phpの538行目あたりに以下の記述を追加しました。閲覧数を記録するファイル(ranking.ini.php)はownerディレクトリに作るとします。`` if(!ADMIN && $UID != ''){ // 閲覧数ランキング用` if(is_file(($ranking = OD.'ranking.ini.php'))){` include_once $ranking; // これで$RANKING配列をゲット` $hit = preg_grep("/(¥d+¥t$UID¥t.+?)/", $RANKING);` if(empty($hit)){` array_push($RANKING, "1¥t$UID¥t$pm_link¥t$_title");` rewrite_ini($ranking, $RANKING);` } else {` $ix = array_keys($hit); $ix = $ix[0];` list($count,) = explode("¥t", $RANKING[$ix], 2);` $RANKING[$ix] = (++$count)."¥t$UID¥t$pm_link¥t$_title"; // ヒットした数の更新` $RANKING = array_slice($RANKING, 0, 100); // とりあえず100件も登録すればOKだろう` rsort($RANKING, SORT_NUMERIC); // 大きい順にソート` rewrite_ini($ranking, $RANKING);` }` } else rewrite_ini($ranking, '', '$RANKING'); // 記録保持ファイルがないなら作成` } `` テーマファイルのtemplate.php には新たな変数%_RANKING:1:人気エントリー:1_% を用意しておきます。具体的には以下のような感じ。つまりranking という新たなIDが加わります(pprankingの方が良いかなぁ)。``<div id="ranking ">%_RANKING:1:人気エントリー:1_%</div><!--#ranking--> `` そして、この変数を変換する関数を用意しておきます。``function showRanking(){` if(is_file(($ranking = OD.'ranking.ini.php'))){` include_once $ranking;` if(!empty($RANKING)){` $h = NL;` foreach ($RANKING as $i => $r){` if($i >= RECENT_ENTRIES) break; // 表示させる数はエントリー記事の表示数と同じ設定にしておく` list($count, $uid, $pmlink, $title) = explode("¥t", $r, 4);` $h .= ' <li><a href="'.$pmlink.'" title="'.date('Y年n月j日の投稿', $uid).'">'.$title.'</a> <span title="閲覧数">'.$count.'</span></li>'.NL;` }` return $h;` }` }`} `` 後は、テーマファイルのCSSファイルもちょいといじって出来上がりです。とりあえず、この改造を施したutils.phpとBasicテーマのtemplate.php及びCSSファイルを添付しておきますね。``[file:1250196829_template.php:6.2/]`[file:1250196829_basic.css:36.9/]``[file:1250196829_utils.php:95.7/]|martin|1|1|||
[29] => 1246908845|開発日誌|アクセス解析で除外キーワード| こんばんは。おとといに引き続き、アクセス解析関連ネタ。`` 現状、ppBlogでは、登録したIPアドレスによって、アクセスログに記録するかどうかを判断する機能をつけていますが、IPアドレスを逐一登録していくのは、そう楽ちんな作業ではありません。なので、stat/log.phpの方で、``if(strpos($ua, 'bot') || strpos($ua, 'Bot')) $ip_accept = FALSE; ``みたいな記述をして、アクセスログへの記録を避けることができますよ、というのをいつか記事にしました。でも、ユーザーの方に直接 log.php をいじってね、というのも不親切だなぁと感じていたんで、管理画面の方で、統計除外したい任意のキーワードを指定できるようにしました。`` 検索エンジンのクローラーなどは、来てくれるのはありがたいのですが、それらをすべてアクセスログに記録していたら、ログの肥大化に繋がります。なので、これを避けよう、というのが基本にあります。この手のクローラーは、分かりやすいユーザーエージェント名を名乗ってくれることが多いです。例えば、グーグルなら、`Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) `Yahoo!なら、`Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp) `MSNなら、`msnbot/1.1 (+http://search.msn.com/msnbot.htm) `という具合です。なので、これらの文字列に含まれる単語を指定しておくことで、アクセスログへの記録を回避できます。例えば、bot というキーワードを登録しておけば、それだけで、この文字列を含んでいるGoogleとMSNのクローラーの足跡を断つことができます。``` 管理画面でのスクリーンショットを載せときますね。`` `` `` 尚、登録したキーワードは、IPアドレス除外と同じ設定ファイルnotcount.ini.php に記録するようにしたので、特にこの処理を入れたことによるスピード低下はほとんどないと思います。[署名/]|martin|1|1|||
[30] => 1246767240|開発日誌|表示記事数を読み手が設定| おはようございます、martinです。現状、管理画面で設定出来る、記事ボックス表示モード時の記事数ですが、ユーザーの方からのご提案で、これを読み手が自由に設定できたら良いなぁ、とありました。`` なのでやってみました。`` `` 仕様上、表示数はいくらでも指定出来ますが、100件づつ表示とかしたら表示にえらく時間がかかってしまったので(当然ですが)、とりあえず30件を上限としています。ボックス表示で30件もあれば十分かなとは思いますので。`` v1.7/1.8系の方は、以下の添付ファイルで試すことができます。いつでも戻せるように、元のutils.phpのバックアップは取っておいて下さい。``[file:1246767240_utils.php:94.5/]|martin|1|1|||
[31] => 1246735109|開発日誌,PHP|gethostbyaddrのキャッシュ化| こんばんは、martinです。前回に引き続いて、高速化のお話。`` ppBlogは、それなりに高機能だと思っているアクセス解析機能が初めから付いていますが、ログ取得のためにアクセス時のIPアドレスから、PHPのgethostbyaddr() 関数を使ってホスト名を取得できれば取得するようにしています。gethostbyaddr()関数はDNS サーバに問い合わせてIPアドレスに対応するホスト名を調べる、いわゆる逆引きを行ってくれます。なので、ともすると、この段階がページ表示スピードのボトルネックになる可能性があります。`` なので、IPアドレスに対応するホスト名のキャッシュ化を考えてみました。情報をどこに保持するかですが、ひとつのIPアドレスに対して、ひとつの対応するホスト名さえ分かればOKなので、ここはクッキーに情報を保持するのが良さそうです。その際に、「生」の値を保持するのは、何となく気持ち悪いので暗号化してクッキーに保持するようにします。`` アクセス解析のための情報取得は、stat/log.php が担当してるのですが、ここ1-2日間、log.phpを結構書き換えています。IPアドレス/ホスト名のクッキー化に関する記述は、今のところ以下のような感じです。``/*` * gethostbyaddrのキャッシュ化による高速化。クッキーによる実装。` * 暗号化されたホスト情報がクッキーに入ってるなら、それを取得。そうでなければ逆引きをする。`*/`if(isset($_COOKIE['PPBLOG_DNS']) && strpos(($DNS = ' '.my_decrypt($_COOKIE['PPBLOG_DNS'])), $ip)){` list($host,) = explode("¥t", ltrim($DNS), 2); // ホスト名の取得。gethostbyaddr()関数よりずっと高速。`}``if(!isset($host)){ // クッキーに記録されていなければ、そこで初めてgethostbyaddr()関数を使う` $host = ($host = gethostbyaddr($ip)) ? $host : $ip;` if($host != '') setcookie('PPBLOG_DNS', my_encrypt("$host¥t$ip"), time() + 30*24*3600);`} `` gethostbyaddr()関数と比べて、どれくらい速いか計測したところ、少なくとも40倍以上高速 になりました。この実装で問題がないようであれば、次期バージョンアップ時に採用したいと思っていますが、試してみたいという方のために添付しておきます。単なる上書きで良いです。その際、元のlog.phpのバックアップは取っておいて下さい。[署名/]``[file:1246735109_log.php:5.4/]|martin|1|1|||
[32] => 1246700189|開発日誌,PHP|array_shiftとreset| こんばんは、martinです。ppBlogでは、「軽快な動作」を常に念頭において開発しています。PHPには、実に様々な関数が最初から提供されていて、似たような振る舞いをする関数も結構あります。なので、こういう場合は、それぞれの関数で処理時間を計測して、より処理速度が速いほうを採用するようにしていますが、最近、そんなやつをひとつ見つけました。`` ppBlogでは、内部でいろんな配列が定義されていて、それを切ったり貼ったりして使用してます。その際に、配列の先頭の要素を取り出すという処理を至る所でしているのですが、これまではarray_shift を用いていました(というかそれしか知らなかった)。`` ` array_shift() は、array の最初の値を取り出して返します。配列 array は、要素一つ分だけ短くなり、全ての要素は前にずれます。 数値添字の配列のキーはゼロから順に新たに振りなおされますが、 リテラルのキーはそのままになります 。
` 引用元: PHP: array_shift - Manual ` `` 上の赤字にあるように、元の配列を変えてしまうという点に留意していれば、便利な関数です。で、最近別の似た振る舞いをする関数を見つけました。reset() 関数です。`` reset() は、array の内部ポインタの先頭の要素に戻し、配列の最初の要素の値を返します 。
` 引用元: PHP: reset - Manual ` `` 何となく、内部ポインタを先頭に移すんだなという印象でファイルオープンfopen() などを使う場面ぐらいでしか使わないと思っていたのですが、その要素も返すんですね。``<?php`$stack = array("orange", "banana", "apple", "raspberry");`$fruit = array_shift($stack); // 結果はorange` // $stackはarray("banana", "apple", "raspberry")になる`?> ``<?php`$stack = array("orange", "banana", "apple", "raspberry");`$fruit = reset($stack); // 結果はorange、$stackは元のまま`?> `` さてどちらが処理速度が速いかというと、ローカルな環境(PHP5.2.9)では、実はそんなに変わりません。100万回の試行で、前者が3.4秒のところが後者のreset()関数だと3.2秒と、ちょっとだけ速いかなという感じです。でもタイピングも少なくて済むし、こういうのの積み重ねが大事なので、今後はreset()を使うようにしようと思います。余談ですが、ラズベリー(raspberry)の綴りはちょっと意外でした。 `` ここでひとつ押さえておくべきことは、上の$stack の例のように、もし配列のキーが定義されていない、つまりキーインデックスがゼロから始まるような配列ならば、わざわざ関数を持ち出さなくても、`<?php`$stack = array("orange", "banana", "apple", "raspberry");`$fruit = $stack[0]; // 結果はorange、$stackは元のまま`?> `でこと足りるということです(これだと100万回の試行では2.4秒と最速)。これで済む場合はそうしますが、ppBlogの内部では、``Array`(` [3] => orange` [11] => banana` [23] => apple` [29] => raspberry`) `みたいに、キーの添え字にも意味がある処理が多いです。[署名/]|martin|1|1|||
[33] => 1245582119|開発日誌|新しいテーマ: カラム切り替え型| こんばんは。ppBlogのテーマ(スキン)は、数少ないのですが、以前作りかけだったのを少しいじって、とりあえずアップしておきます。見栄えはFirefoxで確認しています。一応、IE6向けの記述も入れていますが、細かいところまでは追っていないです。`` 主な特徴を挙げると、``` 3ペイン(3カラム)と1カラムの切り替え型。 ` ソース上は、メインコンテンツ(つまりブログ記事)が、サイドバー内容よりも先行する。 ` テキストエディタで、幾つかの色を置換するだけで、ぐっと見栄えが変わるので、何パターンか配色を用意しやすい。 ` カラムの切り替え情報をクッキーに保存するので、ページを更新しても、1カラムなら1カラムを再現する(タイムラグがあってスムーズではないですが・・・)。 ` ``ってとこです。テーマに含まれるCSSファイルを見ると分かりますが、先頭に``/*` 基本カラー: beige` 基本リンクカラー: darkslateblue` 基本 a:hoverカラー: palevioletred` 基本 li:hoverカラー: #feffe9`*/ ``のようにコメントを入れています。お使いのテキストエディタで、この部分にある色を一括置換(例えば、beigeをyellowに連続置換)するだけで、ガラッと見栄えが変わります。今どきのテキストエディタでは、連続置換・一括置換はついていることが多いと思いますが、個人的に愛用しているのは、フリーとは思えないぐらい使い勝手の良いタブ型エディタであるYokka さんの[g]DeuxEditor[/g](ドゥエディタ)です。差分チェック機能なども付いていて、とにかく高機能です。`` とりあえず4種類ほど、配色を変えたパターンを用意したので、それぞれのスクリーンショットを付けておきます。`` `` `` `` `` 現状、ppBlogでは、テーマ1つにつき、テーマディレクトリ1つが対応しているのですが、テーマの情報を保存しているowner/theme.ini.php を直接いじることで、同じテーマディレクトリを使い回す ということが可能です。例えば、この新しいテーマのディレクトリ(フォルダ)名は、3colv2 なのですが、その中に4種類の配色パターンを指定したCSSを入れておけば、テンプレートのtemplate.phpや画像を入れているImagesディレクトリなどは使い回しができます。具体的には、以下のようにowner/theme.ini.php をいじると良いです(このサイトでの指定例)。```<?php $THEME_LIST = array(`'ベーシック'=>'theme/basic/basic.css',`'3pane'=>'theme/3pane/3pane.css',`'ベージュ'=>'theme/3colv2 /beige.css',`'モスグリーン'=>'theme/3colv2 /mossgreen.css',`'ラヴェンダー'=>'theme/3colv2 /lavender.css',`'ロースピンク'=>'theme/3colv2 /rosepink.css',`);?> `` 共通して、3colv2 というディレクトリを指定している部分がポイントです。`` とりあえず、3colv2のフォルダの中に、4種類のCSSファイルを付けた状態で添付しておきますので、お好みで好きなのを選んだり、色んな色を試して下さい。後、参考までにこのサイトのowner/theme.ini.php も添付しておきます。``[file:1245582119_theme.ini.php:0.3/]``[file:1245582119_3colv2.zip:76.7/]|martin|1|1|||
[34] => 1238977989|開発日誌|しぃペインターのアニメーションを入れてみる| こんばんは。しぃペインターのアニメーションを入れてみます。比較的簡単に実装できた様です。しぃペインターのアニメーションファイルであるPCHファイルを再生するには、専用のビューワーであるPCHViewer.jar が必要で、後、補助として、res.zip ファイルも必要のようです。これらのファイルは、しぃちゃんさんのサイト からダウンロード出来ます。``` これら2つのファイルをmodulesディレクトリ に入れます(res.zipは解凍せずにこのままで)。後は、作成したPCHファイルを、以下の形式で指定すればOKです。``[media:ppdraw1238971539.spch:300:pch/] `` わざわざ、この形式を書き出すのはメンドイので、「動画サイト選択」のプルダウンメニューに「PCHファイル」という項目を追加しました。これで、上の例で言えば、テキストエリア内にppdraw1238971539.spch という文字列があれば、それを上のmedia形式に書き換えます。``` ``[media:ppdraw1238971539.spch:300:pch/]`` 尚、生成されたPCHファイルは、初めは、キャッシュディレクトリに作られます。便利なことに、このPCHファイルは、しぃペインターで呼び込むことが可能です。なので、レジューム機能 (再開)も利用できるようにしてます。管理画面エディタの「しぃペインター」ボタンを押すと、このディレクトリにあるPCHファイルをリスト表示するので、その中から任意のPCHファイルを選択できます。また、この画面で「通常モード」か「プロモード」かを選べるようにしました。|martin|1|1|||
[35] => 1238707452|開発日誌|ppBlogへのしぃペインターの組み込み| こんばんは。お絵かきツールであるしぃペインターをppBlogに組み込むテストです。`` 手順は以下の通り。``` しぃペインターの配布サイト からsptr_all1114.zip を入手する。 ` ppdraw.php とspainter_all.jar (しぃペインターで必要なのはこのファイルだけ)をサーバー上のトップディレクトリにアップロード。 ` upload.php とwrite.inc.php とedit.inc.php をお絵かき用のものへ更新する。 ` `` 以上の手順を踏むと、以下のようなボタンが、書き庫画面に現れます。`` `` このボタンを押すと、下図のようなしぃペインターのお絵かき画面が出てきます。適当に絵を描いて、しぃペインターの「投稿」ボタンを押すと、普通にppBlogで画像をアップロードした時のような画面になるので、後はいつも通りです。`` `` 下の絵は、これで描きました。投稿の幅が拡がって良いかなと思います。`` `` これらのファイルを添付しておきます[ppdraw.php, upload.php, modules/write.inc.php, modules/edit.inc.php]。こららのファイルは、ppBlogのバージョンでそう変わらないと思うので、バージョン1.6以上とかなら動く気がしますが、未確認なので、上書きの際は元のファイルのバックアップを取って置いて下さい。``ppdraw.phpの21行目あたりにユーザーで設定出来る箇所があります。```define('WIDTH', 300); # 出力される画像の縦サイズ`define('HEIGHT', 300); # 出力される画像の横サイズ`define('MODE', 0); # 通常モード[0]か、プロ仕様[1]か `` しぃペインターのモード(通常版かプロ版か)を指定出来ます。最初は、通常版の指定です。こちらの方が分かりやすいかなと思いますので。しぃペインターの使い方については、以下のリンクが詳しいです。``→しぃペインターの使い方(しぃペインター講座) ``[file:1238707452_ppdraw.zip:20.2/]|martin|1|1|||
[36] => 1238300138|開発日誌,JavaScript|VMLやSVGを用いた角丸コーナー,rounded-corner| おはようございます。時間があるときに、以下のようなサイトを作成しているのですが、この2枚のスクリーンショットは、違うところがあります。どこが違うのかというと、2枚目のやつは、ボックスのコーナーが丸っこくなっていて、いわゆる角丸コーナーと言われるものになっています。`` `` `` ちょっとお洒落っぽいサイトデザインにしようと思っているのですが、そのためには、角張ったデザインよりも、角が取れたデザインの方が良いかなと考えました。で、角丸コーナーは、FirefoxやWebKit系のSafariやChromeは、以下のような感じでCSSでの指定が可能です。``-moz-border-radius: 10px; // Firefox`-webkit-border-radius: 10px; // Webkit系 ``問題は、これらのCSSに対応していないOperaやIEです。Operaは、近い将来にサポートするでしょうけど、IEは、今後数年は期待できないかもです。なので、これら2つのブラウザに対しては、JavaScriptを通じてのアプローチを取ることになります。`` IEでは、VMLを利用するのがよさげです。しかも角丸コーナーのためにあるようなroundrect というのが予め実装されているので、これを使うのが簡単そうですが、例えば最初に挙げたサイトショットにあるように、ナビ―ゲーションタブの上側だけ丸っこくしたいとかいう場合の制御が難しいです。なので、VMLを使うにしても、もうちょっと、凝ってみることにします。そもそも角丸コーナーを実現するには、以下のようなアプローチを取るのが自然でしょう。`` `` 要は、4つの各コーナーに小さい円を描いて、それをクリッピングすれば良いわけです。これなら、ボーダー半径は、FirefoxやWebkit系で指定する値と同様に振る舞うことが期待出来ます。で、それを実際に書き下したのが以下。``<div style="background:#fffacd; position:absolute; right:-20px; bottom:-20px; width:50px; height:50px; clip:rect(25px 50px 50px 25px);">` <v:group style="width:50px; height:50px; position:absolute;" coordsize="50,50">` <v:oval fillcolor="#fff" strokeweight="20px" strokecolor="#ffd700" style="left:9px; top:9px; width:30px; height:30px;" />` </v:group>`</div> `` これをIEで見ると、以下のように見えます。なかなか良い感じですね。`` `` 残りの角についても同様にすればOKです。ただし、IEのVMLバグなのかどうか分かりませんが、作成したVML画像の位置が1ピクセルぐらい微妙にずれる場合があるようです。理論的には、OKのはずなんですが。。`` さて、Operaの場合はどうでしょうか。OperaはVMLはサポートしませんが、代わりにSVGをサポートします。なので、これを用いて、上で述べたようなアプローチを取ればOKですね。大体以下のようなスクリプトでOKでしょう。````function svg_corner(id, location, r, obg){` var d = document, e = d.getElementById(id);` if(e.currentStyle.position == 'static'){` e.style.setProperty('position', 'relative', null);` }` r = r || 10;` var svg = d.createElementNS('http://www.w3.org/2000/svg', 'svg');` svg.style.setProperty('position', 'absolute', null);` var ibg = e.currentStyle.backgroundColor;` ibg = ibg == 'transparent' ? '#fff' : ibg;` if(!obg){` var p = e.parentNode;` while(p && p.currentStyle.backgroundColor){` obg = p.currentStyle.backgroundColor;` if(p.nodeName == "HTML") break;` if(obg && obg != "transparent") break;` p = p.parentNode;` }` }` obg = (!obg || obg == "transparent") ? "#fff" : obg;` var bc = e.currentStyle.borderColor;` bc = (!bc || bc == "transparent") ? "#fff" : bc;` var bw = parseInt(e.currentStyle.borderWidth);` var rect = d.createElementNS('http://www.w3.org/2000/svg', 'rect');` var oval = d.createElementNS('http://www.w3.org/2000/svg', 'circle');` var attr = [];` switch (location){` case 'tl' : attr = [r + bw/2, r + bw/2, 'top', -bw, 'left', -bw]; break;` case 'tr' : attr = [0, r + bw/2, 'top', -bw, 'right', -bw]; break;` case 'bl' : attr = [r + bw/2, 0, 'bottom', -bw, 'left', -bw]; break;` case 'br' : attr = [0, 0, 'bottom', -bw, 'right', -bw]; break;` }` oval.setAttribute('fill', ibg);` oval.setAttribute('cx', attr[0]); oval.setAttribute('cy', attr[1]);` oval.setAttribute('r', r);` oval.setAttribute('stroke', bc); oval.setAttribute('stroke-width', bw + 'px');` rect.setAttribute('fill', obg);` rect.setAttribute('width', r * 2 + bw + 'px'); rect.setAttribute('height', r * 2 + bw + 'px');` svg.appendChild(rect);` svg.appendChild(oval);` svg.style.setProperty(attr[2], attr[3] + 'px', null); svg.style.setProperty(attr[4], attr[5] + 'px', null);` svg.style.setProperty('width', r + bw/2 + 'px', null); svg.style.setProperty('height', r + bw/2 + 'px', null);` e.insertBefore(svg, e.firstChild);`}` `` これらをまとめると、以下のようなデモンストレーションが出来ます。このデモでは、ID指定した要素に対して角丸を発動していますが、特定のクラス名を持ったものに対して、ということも簡単に出来るでしょう。``どのブラウザでもほぼ見た目が同じな角丸コーナーのデモ
`` 上のサンプルでは、ついでにFirefoxやWebkit系でも、スクリプトでボーダー属性を指定するようにしています。このふたつ、指定の仕方が微妙に違うんですよねぇ。ちょっとはまりました。以下の感じ。`document.getElementById(id).style.WebkitBorderTopLeftRadius = radius + "px"; // Webkit系`document.getElementById(id).style.MozBorderRadiusTopleft = radius + "px"; // Firefox。leftのLも小文字。 `` なお、OperaでのSVGの使い方は、「Operaで丸角を実現するCSSを試してみた (解決) 」や「角丸にするためにライブラリを作ってみる 」が参考になりました。|martin|1|1|||
[37] => 1237834697|開発日誌,PHP|ppBlogをサーバー上でZIP展開| こんばんは。どうも昨日辺りから自宅のネット接続がとろいです。ppBlogは、ファイル数は390個(決して多くはないと思いますけど)近くあるのですが、それが昨日は全部アップロード出来ずじまい。愛用している[g]FFFTP[/g]の転送画面が何度も途中でフリーズしたようになってました。昔、28.8kbps?ぐらいのモデムでピーガラガラとかやってたのを思い出しはしませんでしたが。`` というわけで、ブログシステムというものは、多機能になればなるほど、当然のようにそのサイズが肥大化していきます。なので、サーバー上に、圧縮されたZIPファイルをさくっとアップロードして、そこで展開するのが楽だよなぁ、と思ったので、PHPの充実したオンラインマニュアルを片手に、そういうスクリプトを書いてみました。最初に書いたのが以下です。ローカルのテスト環境でわけなく作動したので、こりゃいけるとサーバー上で試したら、zip_open 関数がないと怒られました[zzz/]```function my_unzip($zipFile=''){` $zip_dir = getcwd().'/'; // カレントディレクトリの取得` if(is_dir(str_replace('.zip', '', $zipFile))){ // 既に展開されたディレクトリがあるならば` exit("Already exists!");` }` $i = 0; // どれくらいファイルがあるのか知りたい` if($zip = zip_open($zip_dir.$zipFile)){` while($zip_entry = zip_read($zip)){` $file = zip_entry_name($zip_entry);` $zdir = $zip_dir.dirname($file);` if(!is_dir($zdir)){` @mkdir($zdir, 0777); // ディレクトリないなら作成` echo "Directory: ".dirname($file)."/ created.<br />¥n"; // メッセージ表示` }` if(zip_entry_open($zip, $zip_entry, 'rb')){ // ファイルの書き出し` if($fp = @fopen($file, 'wb+')){` fputs($fp, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));` fclose($fp);` echo " File ".++$i.": $file created.<br />¥n";` }` }` zip_entry_close($zip_entry);` } #while` }` zip_close($zip);` return TRUE; // 無事に終わったらTRUEを返す`}` ``これを以下のようにしてローカルで走らせました。``if(my_unzip('ppBlog180b.zip')){` echo "Successfully extracted!¥n";`} else echo "Failure!¥n";` ``したら、ファイル数が390個近くあることが判明。で、実際にオンラインのサーバー上でもやってみたら駄目だったわけです。なので、シェルコマンドでトライしてみました。```$zip_file = getcwd().'/ppBlog180b.zip'; // 展開するファイルを指定``function unzip($zip_file){` return shell_exec("unzip $zip_file"); // UNIX系には、まず付いてるであろうunzipを使う`}``if($zip = unzip($zip_file)){` echo "<pre>$zip</pre>¥n"; // これでずらっと展開されたファイルが表示される` echo "$zip_file: Successfully extracted! ";` echo '<a href="./ppBlog180b/install.php">installation</a>'; // 続けてppBlogのインストール画面へ誘導`} else{` echo("Failed to extract: $zip_file¥n");`} ``そしたら、今度は上手く行きました。すべてのファイルがそっくりサーバー上で展開されていました。これは楽チンですねぇ。上のスクリプトは、単にZIP圧縮されたフォルダを展開するだけなので、サーバー上に作成されたディレクトリは、圧縮前のフォルダの名前と同じになります。多分、copyコマンドとかchdirで、展開先やら名前を指定できるでしょうね。`` 一応、この簡単なスクリプトを添付しておきます。お使いのサーバーで動くかどうかは保証しませんが。。と、その前にppBlog180b.zipがないことには・・・。``[file:1237834697_ppblogunzip.php:0.6/]|martin|1|1|||
[38] => 1237810287|開発日誌,JavaScript|正規表現を使わないCSS3対応の「属性限定」セレクタ関数| ppBlogでは、不十分ですけどCSS3対応のセレクター関数を実装していたんですが、これを大幅に書き換えました。従来は、XPathが使えるブラウザであれば、CSS3のセレクタをXPath用に変換して、意中の要素を取り出したりしていました(スピード面でなかり有利)。でも、document.querySelectorAll をサポートするブラウザが当たり前になってきたので、少なくともppBlogでは、XPathは不要という結論に達しました(今やFirefoxのためだけに用意してる感じで、しかも次期v3.5では間違いなくquerySelectorAllがサポートされるでしょうから)。`` ppBlogで使っている要素抽出のためのセレクターは、大体以下のような感じです。``` o("#ID") 系 // IDを持つ要素を取り出す ` o(".className") 系 // 特定のクラス名を持つ要素を取り出す ` o("a[rel=edit]") // 属性セレクター系 。A要素でrel="edit"のやつを取り出す ` o("textarea[id^=Page]") // 属性セレクター系 。テキストエリア要素でID名がPageで始まる要素を取り出す ` ``とまぁ、こんな感じで、ほぼ頻度順になってて、圧倒的にID名抽出が多いです。なので、別に高機能なセレクター関数は必要ないわけで。XPathへの変換にえらくファイル容量を割いていたんですが、それをばっさり削ったんで、だいぶシェイプアップされました(oParts.js)。`` ただ、属性セレクター(上のリストの下2つ)は、今後、色々使い道がありそうなので、これはスピードも考慮した関数を実装しました。以下のような関数です。正規表現を使っていないので、速度面で有利です。面白いことに、FirefoxよりIE6-8の方が高速に動きます 。別に詳しく計測した訳ではありませんが、属性セレクターに限定すれば最速の部類ではないかと思っています(XPathやquerySelectorAllを使わないレガシーな系で)。```// cache = {}; // キャッシュ使うなら`function queryByAttributeSelector(rule){` var apos = rule.indexOf('[');` var tag = rule.slice(0, apos); // タグ名を抽出。` var attr = rule.slice(apos + 1, -1); // 属性を抽出` attr = (attr.indexOf('][') > 0) ? attr.split('][') : [attr];` var s = '', e, k, ks, v, z, i = 0, l = attr.length;` // if(!cache[rule]){ // キャッシュ使うなら` for(; a = attr[i++];){` e = (i != l ? ' && ' : '');` z = a.split('=');` if(z[1]){` k = z[0], ks = k.slice(-1);` v = z[1].indexOf('"')===0 ? z[1].slice(1, -1) : z[1];` k = k.indexOf('class') !== -1 ? k.replace('class', 'className') : k;` switch (ks){` case '^' : k = k.slice(0, -1); s += 'n["'+k+'"].indexOf("'+v+'")===0' + e; break;` case '$' : k = k.slice(0, -1); s += 'n["'+k+'"].lastIndexOf("'+v+'")===(n["'+k+'"].length - "'+v+'".length)' + e; break;` case '~' : k = k.slice(0, -1); s += '(n["'+k+'"]=="'+v+'" || n["'+k+'"].indexOf("'+v+' ")===0 || n["'+k+'"].indexOf(" '+v+' ")!==-1 || ((z=n["'+k+'"].indexOf(" '+v+'"))>0 && !n["'+k+'"].charAt(z+"'+v+'".length+1)))' + e; break;` case '*' : k = k.slice(0, -1); s += 'n["'+k+'"] && n["'+k+'"].indexOf("'+v+'")!=-1' + e; break;` case '|' : k = k.slice(0, -1); s += '(n["'+k+'"]=="'+v+'" || n["'+k+'"].indexOf("'+v+'-")!= -1)' + e; break;` default : s += 'n["'+k+'"]=="'+ v +'"' + e;` }` } else {` s += 'n["'+(a==='class'?'className':a)+'"]' + e;` }` }` /*cache[rule] = s; // キャッシュ使うなら` } else {` s = cache[rule];` }*/` var r = [];` var items = document.getElementsByTagName(tag||'*'), j = 0, n;` var v = new Function('n', 'return ('+s+')');` for (;n = items[j++];){` if(v(n)){` r[r.length] = n;` }` }` return r;`} `` 工夫した点は、indexOf やらlastIndexOf の積極的活用です。split関数は、正規表現を用いない文字列での分割は、用いる場合より何倍も高速です。後、細かい速度の改善については、uupaaさん のエントリ [latest log]が非常に参考になりました。``CSS3の「属性 」セレクターをほぼ網羅していると思いますが、とりあえずhttp://mootools.net/slickspeed/にある属性セレクターはすべてパスします(ただし、div[class!=made_up] は、CSS3にはなさそうなので未対応)。`` 上のソースコメントをみれば分かりますが、キャッシュを有効にするとより速くなります。でも別になくても良いかなと思ってます。細かい点を言えば、A要素のREL属性なんてのは、大文字小文字を区別しないようですが、そこまでは追ってません。要は、ppBlogで動けば良いので。`` ppBlog1.8.0での実装は、上のソースをベースにしたものになっています。|martin|1|1|||
[39] => 1236976209|開発日誌,JavaScript|テキストエリアの自動リサイズ再び,autofit-textarea| 以前、テキストエリアのサイズを文章の長さに合わせて変えるスクリプトを考えて、それをppBlogのエディタにも採り入れているのですが、それは意図した様に動くには動くのですが、えらく力業なスクリプトでした。その恥ずかしいスクリプトは、ここ に置いてます[はてさて/]`` 記述も長くてスマートでないし、もっと簡単に出来ないかなぁと考えてみましたが、要は、自動調節というのは、テキストエリアのスクロールバーが表示されなくなるまでエリアを伸ばすということなので、その考えで行けば簡単でした。以下のような記述でいけますね。``function autofit(el){` if(el.scrollHeight > el.offsetHeight){` el.style.height = el.scrollHeight + 'px';` } `} ``element.scrollHeight で、目的のテキストエリアの、スクロール分も含めた高さ (+ボーダー幅)を取得できます。で、element.offsetHeight で、見た目の高さを取得できます。なので、スクロールバーが表示されている状態というのは、文章が長くて表示しきれない状態なので、じぁ、テキストエリアの高さをscrollHeight に合わせれば良い、ということになりますね。なんで、こんな簡単なことに気が付かなかったかなぁ。まず、このデモを見てみましょう。```AutoFit
`[script]`function autofit0313(el){` if(el.scrollHeight > el.offsetHeight){` el.style.height = el.scrollHeight + 'px';` }`}`function autofit03132(el){` if(el.scrollHeight > el.offsetHeight){` el.style.height = el.scrollHeight + 'px';` } else {` while (el.scrollHeight - 50 < parseInt(el.style.height)){` el.style.height = parseInt(el.style.height) - 50 + 'px';` }` arguments.callee(el);` }` el.focus();`}`[/script]`` とりあえずは、これでよさげですが、もうちょっといじってみましょう。例えば、この文章をコピペして、元の文章の下に貼り付けると、表示領域からはみ出るので、自動的にスクロールバーが表示されると思います。なので、ここでもう一度「AutoFit」ボタンを押すと、テキストエリアが広がります。次に、この貼り付けた文章を削除してみて下さい。テキストエリアが広がった分、下に大きな余白が出来ますね。今度は縮めようと再度ボタンを押してもテキストエリアのサイズは変わりません。これは、このautofit関数の定義からして当然なのですが、気持ちとしては、今度は逆に縮んで欲しいなと。では、どうするか?`` 強制的にスクロールバーを表示させる状態に持っていって、そこでこのautofit関数をかませば良いです。スクロールバーを表示させるには、意図的にテキストエリアの縦サイズを小さく取ればよいわけです。なので、極端な話、``element.style.height = '1em'; ``とでもして、つぎにautofit()を呼び出せばOKですが、これだと見た目にテキストエリアがスプラッシュみたくなるので、なるべく最小量のサイズ変更でいくには、次のような感じで良いかなと思います。````/* AutoFit関数その2 */`function autofit2(el){` if(el.scrollHeight > el.offsetHeight){` el.style.height = el.scrollHeight + 'px';` } else {` while (el.scrollHeight - 50 < parseInt(el.style.height)){` el.style.height = parseInt(el.style.height) - 50 + 'px'; // 適当に50pxずつ` }` arguments.callee(el); // 高さを縮めてスクロールバーが出てくるタイミングで呼び出す` }` el.focus();`} `` 以下に、これを適用したものを付けておきます。上の関数との動作の違いが分かると思います。```AutoFit 2
`` この関数をonkeyupなどのキーイベントと結びつけておけば、入力に合わせて自動的にサイズが変わるテキストエリアの出来上がりです。これのデモを以下に挙げておきます。`` →http://p2b.jp/demo/autofit-textarea.html|martin|1|1|||
[40] => 1236951518|開発日誌|IE8はGoogle Chrome、Firefoxよりも高速って,IE8-faster-than-oher-browsers| ITmediaより。IE 8はGoogle Chrome、Firefoxよりも高速――MSが独自テストの結果を発表 `` タイトルだけ見ると、果たしてJavaScriptの話なのか(まぁ、これはないと思うけれど)、それともレンダリングの話なのかと思ったけれど、どうやらページの読み込み速度の話みたい。ページ読み込み速度って、レンダリング速度とは別物なのだろうかと思いつつ、確かに、ローカルな環境で、主要なブラウザを使ってppBlogの動作チェックしていると、IE8のレンダリングが速くて、思わず「ほう」とうなってしまうことが多々ある。いつぞやのOperaを彷彿とさせる。でも、まだ、細かいところで、おやっと思う動作があるんだけれど。|martin|1|1|||
[41] => 1236707125|開発日誌,JavaScript|コメント読み込み時にスクロール| ppBlogでは、コメントやトラックバックが付いている記事には、それを記事の下の方に表示するレスポンス展開ボタンが付いてます(複数記事モードのとき。単独表示では、最初からコメント類は表示されている)。ここで、ボタンをクリックすると、Ajax経由で動的にコメントを読み込むので、わざわざページをリロードさせる必要もなくスムーズにコメントなどを読むことができます。`` 現行では、このボタンをクリックしてデータを読み込むと、コメントエリアにフォーカスが移っていたと思いますが(ウィンドウがスクロールする)、これが、瞬時でピクッと移るために、何となく読み手の視点が混乱するというか、一瞬、何が起こったのか分からなくなるかもしれないと思い、このフォーカス移動を止めてみました。`` すると、特にウィンドウのスクロールを伴うことなく、展開されたコメント・トラックバックがボタンの下に表示されて良い感じです。でも、ひとつ問題があって、もし、このレスポンス展開ボタンをブラウザ画面の結構下の方でクリックすると、展開されたコメント類がブラウザ画面の領域下に表示され、これはこれで、何も展開されてないように見えるので、読み手を困惑させる可能性があります。`` なので、Ajaxで読み込んだデータを展開した際に、それらがウィンドウの枠外であるときに限って、そのエリアまでスクロールさせるようにしました。かといって、単なるフォーカスの瞬間移動では、最初に述べたように、これも読み手を惑わせるかもしれないので、瞬時に移動ではなくて、スクロール制御するようにしてみました。以下のようなスクリプトでいけます。``var wscY = oParts.metrics(3); // ウインドウのスクロール量を取得`var firstComment = o("div.comment-entry", commentsDiv).item(0); // 表示エリアの最初のコメント要素を取得`var diff = firstComment.offset(1) - Number(wscY + oParts.metrics(1)); // 上記コメントを表示させるためのスクロール量を算出``if(diff > 0){` (function(){` var a = 30, s = arguments[0] / a; // スクロール量を適当に分割。ここでは30分割してる ` var yy = []; // 縦移動させるスクロールポイントを入れる配列を用意` for (var i = 0; i < a; i++) yy[i] = wscY + s * i; // 適当に移動ポイントを作成` var i = 0, t = setInterval(function(){ window.scrollTo(0, yy[i++]); if(i >= a) clearInterval(t);}, 1);` }).await(300)(diff + firstComment.rect(1) + 140); // データ読み込み後、300ミリ秒後に発動` }`}); `` データを読み込んでからいきなりスクロールしだすと、それで面食らうかもしれないので、.await(300) と微妙に間を持たせています。`` ここのサイトで、実際にコメントの付いた記事で試せますので、興味のある方は、あえてコメント展開ボタンをブラウザ画面ぎりぎりにセットして試して下さい。|martin|1|1|||
[42] => 1236646850|開発日誌,JavaScript|ChromeでもJS簡易エディタが動くように,chrome-JS-editor| こんばんは。ppBlogでの記事作成は、テキストエリアに、タグ入力支援ツールバーの助けをかりて、(ベタに)ぐいぐい書いていくやつです。以前、IEとFirefoxがサポートしていた[g]WYSIWYG[/g](contentEditable/designMode)モードを採り入れようと思いましたが、IEの生成するHTMLソースがひどくて諦めたことを、どこかに書いたと思います。今は、Safariもそれをサポートしているようですが、まぁ現状の、テキストエリア方式でいいんじゃないかなと思っています。その場でプレビュー機能も付いてますし。`` で、このタグ入力支援の機能が、グーグルのChromeでうまく動かないなと前々から認識はしていたんですが、今回調べてみました。IEとの切り分けに、``if(document.getSelection){ // Firefox などIE以外のブラウザ ``としていたのが駄目だったようです。Chromeはこれを無視していたようで。なので、この部分はwindow.getSelection() を使えばOKでした。でも、今や、IE以外のブラウザはみんな同じ仕様に沿ってるようですし(2-3年前はOperaが遅れていた)、IEとそれ以外という大まかな切り分けで行けば良さそうです。なので、よくある、テキストエリアのマウスカーソルのある位置に文字列を挿入するというスクリプトは以下のような感じで行けるかなと思います。ここでは汎用性のあるサンプルを載せます。ppBlog用のlib.jsには、これを若干modifyして載せます。```/* テキストエリアでカーソルで指定したポイントあるいは文字列に新たな文字列を挿入するスクリプト */``var Caret = {` getArea : function(){ return document.getElementById("ta");}, // ID名ta(適当)というテキストエリアを用意` selection : '', // ここに選択したテキストを収納する` get : function(){ // テキスト選択メソッド` var area = Caret.getArea();` /*@cc_on@*/` /*@if(1)` if(!document.selection.createRange()) area.focus();` Caret.range = document.selection.createRange().duplicate();` return Caret.selection = Caret.range.text;` @else@*/` return Caret.selection = area.value.substring(area.selectionStart, area.selectionEnd);` /*@end@*/` },` set : function(string){ // 選択テキストを指定文字列に置換する` var area = Caret.getArea();` /*@if(1)` if(Caret.selection.length > 0){` Caret.range.text = string;` Caret.range.select();` } else {` area.focus();` Caret.range = document.selection.createRange().duplicate();` Caret.range.text = string;` }` @else@*/` if(Caret.selection.length >= 0 && area.selectionStart >= 0){` var s = area.selectionStart, scrollTop = area.scrollTop;` area.value = area.value.slice(0, s) + area.value.slice(s).replace(Caret.selection, string);` area.setSelectionRange(eval(s + string.length), eval(s + string.length));` area.scrollTop = scrollTop; // Firefoxでカーソルがトップに戻らないための処理` area.focus();` } else area.value += string;` /*@end@*/` }`} `` IEだけが違うと分かっているので、条件コンパイルを使って、動作の切り分けをしています。Firefox系で、指定位置に文字列を挿入した後、フォーカスが、テキストエリアのトップに戻ってしまうのを防ぐ処理を入れています。これはFirefox1.5で見られて、今はどうかなぁと思ったら相変わらずでした[zzz/]`` →参考リンク「 Firefoxでテキストエリア内のマウスカーソルが最初に戻ってしまう件 」`` 一応、簡単なデモページを挙げておきます。`` ` →上のスクリプトを使った、簡易JavaScriptエディタ。http://p2b.jp/demo/jseditor.html`` このデモにあるHTMLビューは悪くないなぁ。|martin|1|1|||
[43] => 1236634594|開発日誌|Twitterのリンク先を変更| 昨日かおととい、ブログのエントリーをTwitterに投稿できるTwitThis というTwitterのサービスを知ったんで、それをソーシャルブックマークのアイコンリンクに追加したんですが、これって投稿しようとするとIDとパスワードを求められて、ログイン後、タブを閉じるとセッションが切れるのか、毎回入力画面が出てきます。なので今いちスムーズさに欠けるなぁと思っていたら、普通にTwitterに投稿できる記法があることをついさっき知ったので。``http://twitter.com/home?status=Reading:(エンコードされた文字列) ``で直接投稿できるみたいです(ログイン状態を保持していれば)。なので、これに変えました。投稿時のスクリーンショットを挙げときます。キャプチャのために開いただけなので、エントリーがダブってるように見えますが。`` `` 後、facebook へのエントリーアイコンも追加してます。こちらフランスのラボでは、多くの人がfacebookを使っていて、自分もその流れにのってアカウントを取得しました。NYやコロンビアに帰った同僚もみんなやってて、元気にしてる様子とか分かるし、便利な時代ですね。うちのボスもよく更新してます。さすがに世界最大の写真共有サイトだけのことはあるなぁと。日本ではどうなんでしょうか。|martin|1|1|||
[44] => 1236556695|開発日誌,JavaScript|正規表現の挙動がブラウザ間で異なる件,regular-expression| ヘッドラインモードでの表示周りを整備していて、記事ごとのスタイルシート指定が効いていなかったので、効くようにスクリプトを書き換えましたが、正規表現周りの挙動がブラウザ間で異なっていて、ちょっとはまったのでメモ。簡単な例を示します。``<script type="text/javascript">`function doRex(){` var example = "J'adore Firefox!"; // I like Firefox!` var RE = /Fire/g;` var result = RE.exec(example); ` if(result) alert("マッチ: " + result + "¥nlastIndex: " + RE.lastIndex);` else alert("マッチしません!:" + "¥nlastIndex: " + RE.lastIndex);`}`</script>`<button onclick="doRex();"> 実 行 1 </button>` ` 実 行 1 `` 上のdoRex()関数を実行すると、最初ボタンを押したときはちゃんとマッチしますが、2回目にボタンを押したときの結果がブラウザで異なります。Firefox3.0.7, Chrome1.0, Opera9.64では、「マッチしない」、IE6-8とSafari4 public betaでは、マッチして1回目と同じ結果です。なぜ、こういうことになるかというと、lastIndex 絡みです。1回目の実行に対して、lastIndex の値が保持されているからです。2回目の実行で、マッチしないとなると、RE.lastIndexはまた0に戻るので、3回目の結果は初回と同じく「マッチ」です。`` でも、疑問なのが、doRex()という関数の中で定義したローカルな変数だから、doRex()を実行する度に、lastIndexの値はリセットされるのが正しい気もするんだけどなぁ。doRex()の中ではなく、グローバルな空間で同様のことをやれば、SafariもIEも2回目は「マッチしない」となり、これは納得できる挙動なんですが。`` では、このブラウザ間の差異をなくすにはどうするか?ひとつは、RE.exec(example) した後に、`RE.lastIndex = 0; // 値をリセット `という記述を加えて、明示的にlastIndexを元に戻す方法。もうひとつは、new演算子を使う方法です。これなら、どのブラウザでも同じ挙動、何度ボタンを押しても、「マッチ」となります。new RegExp("foo", "g") と /foo/g って同じと思っていたんだけど。``[script]`function doRex(){` var example = "J'adore Firefox!"; // I like Firefox!` var RE = /Fire/g;` var result = RE.exec(example);` if(result) alert("マッチ: " + result + "¥nlastIndex: " + RE.lastIndex);` else alert("マッチしません!:" + "¥nlastIndex: " + RE.lastIndex);`}``function doRex2(){` var example = "J'adore Firefox!"; // I like Firefox!` var RE2 = new RegExp("Fire", "g");` var result2 = RE2.exec(example);` if(result2) alert("マッチ: " + result2 + "¥nlastIndex: " + RE2.lastIndex);` else alert("マッチしません!:" + "¥nlastIndex: " + RE2.lastIndex);`}``[/script]``<script type="text/javascript">`function doRex2(){` var example = "J'adore Firefox!"; // I like Firefox!` var RE2 = new RegExp ("Fire", "g"); // new演算子を使用する` var result2 = RE2.exec(example);` if(result2) alert("マッチ: " + result2 + "¥nlastIndex: " + RE2.lastIndex);` else alert("マッチしません!:" + "¥nlastIndex: " + RE2.lastIndex);`}`</script>`<button onclick="doRex2();"> 実 行 2 </button>` `` 上のコードであれば、ブラウザ間の差異がない。`` 実 行 2 `` でも、Safari/IE と Firefox/Chrome/Opera、どっちが正しい挙動なんだろうな。今イチ、すっきりしないです。|martin|1|1|||
[45] => 1236492227|開発日誌|ソーシャルブックマークあたりをいじってる| おはようございます。ソーシャルブックマーク(以下SBM)周りの整備中です。ppBlogでは、はなてやdelicious、Yahooなど主要なSBMへの追加リンクを採り入れたりしてますが、実際のところ、パフォーマンスに問題があって、あまり気軽に使えるものではなかったというのが実情でした。なので、アルゴリズムを見直したり、ちょこちょこ変更を加えながらやってます。`` 現時点で、これに落ち着こうかなと思っているのは、実際にこのサイトで動いているやつですが、複数記事表示の時は、各SBMへのリンクアイコンをその場で(Ajax経由)で生成するようにして、単独記事モードの際に、従来のように最初からアイコンを並べるやり方にしようかなと。`` 後、登録されたブックマーク数の更新タイミングは、基本的に単独記事モードの時に作動するようにして、複数記事モードの際はキャッシュから読み込む方式で。`` 複数記事モードのときには、SBMへのアイコンが表示されていて、マウスオーバーで(実際にはonmousemove)、各種SBMサービスへのアイコンがポップ表示されます。初回だけAjaxで読み込むので、ちょっとタイムラグがあり、後は生成されたレイヤーを表示するので、これは瞬時です。mousemoveで監視していると、ユーザーが意図しないonmousemoveでAjax呼び込みが起動する場合もあるでしょうから、mousemoveの移動量がある閾値に達してから、動作するようにしています。まぁマウスクリックでも良いかなぁとは思いますが。`` 後は、SBMにTwitThis へのエントリーも入れてみました。ちょうど1年ほど前に、動作確認のために、Twitterのアカウントを取得したけれど、まるで活用していなかったんで、こういうお気軽エントリーが出来ると良いかなとは思います。|martin|1|1|||
[46] => 1236256261|開発日誌,JavaScript|写真をお洒落に見せるスクリプトの更新| こんにちは。まだまだ寒い日が続きますね。さて、ppBlogには、以下のような感じで、普通のアップした写真をちょいとお洒落に演出するスクリプトが付いてますが、IE8でエラーが出ていたりしたんで、更新しました。`` ` `` IE8のdocument.querySelectorAll の実装に始まり、Safariもサポート、Firefoxは3.1でサポートするでしょうし、この手の用途には、staticなnodeListでこと足りるので、photo-effect をいうクラス名を付けたIMG要素の検索には、document.querySelectorAllを第一に試すようにしてます。`` 始めは、よくやるように、``var nodes = Array.prototype.slice.call(element.querySelectorAll("img.photo-effect")); `` としたのですが、何故かIE8では、JSオブジェクトがないと怒られて折角のquerySelectorAllが使えません。なので仕方なしに次のようにしました。``var nodes, items = element.querySelectorAll("img.photo-effect"), index = items.length;`while(index) nodes[--index] = items[index]; /* 地道に */ `` IE8でも、Array.prototype.slice.call(arguments) は問題なく作動するのに。。きっと、正式版前のバグなんだろうけど。`` てな訳で、最新版を添付しておきます。ついでに言っておくと、このスクリプトは単体で動作します。ただし、2種類の写真フレームの画像も用意して適切にパスを書かないといけませんが。デフォルトでは、Imagesディレクトリにあるphotoframe.png とstampframe.png の2つです。``[file:1236256261_photoeffect.js:5.2/]|martin|1|1|||
[47] => 1236058224|開発日誌|テーブル型カレンダーを修正,table-calendar| こんにちは。今日はスケジュールの都合で、徹夜で実験のmartinです。徹夜してるとお腹すくなぁ。`` `` さて、前回に続き、カレンダーねたで。前回は、テーブルレスカレンダーということで、OL要素を用いたカレンダーを紹介しましたが、かといってTABLE要素を用いたカレンダーを疎かにするわけではありません。現状、ppBlogでは、テーブルタイプのカレンダーは、大きくボックス型とライン型とがあります。更に、ボックス型には、セレクトボックスを付けるタイプと、そうでないタイプの2種類がありますが、次バージョンでは、カレンダーの種類がぐっと増えて、6種類になりそうです。前回、ちらっと触れましたが、大きな変更点は、曜日の並びを自由に指定出来るようになったことと、後、言語の指定が出来るようになったことです。言語といっても、英語か日本語のインターフェイスか、というだけですが。デフォルトでは、日曜日が週の始まりで日本語表示となります。`` ppBlogが生成するカレンダーのソースを改めて見てみると、すっきりしない点があったり、XHTMLの書式となじんでなかったりする点があったので、PHPのカレンダーのプログラム(calendar.inc.php )を見直して大幅に書き換え、はき出すソースも従来のものと若干変わりました。`` `` カレンダーの種類は、従来通り、template.php で指定出来ますが、およそ以下のような書式になります。``# カレンダーのタイプ (1~4はTABLE要素使用。5, 6はOL要素使用)`# [ 0:非表示,1:ボックス型,2:月日セレクター付ボックス型,3:ライン型,4:ライン型 + セレクター,`# 5:リスト要素仕様, 6:リスト要素仕様 + セレクター]`$_CALENDAR_TYPE = 2; `$_CALENDAR_LANG = 1; # [ 0:英語,1:日本語 ]`$_CALENDAR_START = 0; # [ 0:日曜開始,1:月曜開始,2:火曜開始,etc. ] `` $_CALENDAR_LANG と$_CALENDAR_START という変数が新たに加わりますが、この指定は必須ではありません。`` 実際の出力のイメージは、リンク先で掴めると思います。なるべく構造をシンプルにすることで、特にCSSハックを使うこともなく、各ブラウザでほぼ同じ見栄えになっていると思います。`` [にこっ/]http://p2b.jp/demo/calendar.html|martin|1|1|||
[48] => 1235774435|開発日誌|テーブルレスカレンダーを考えてみる,tableless-calendar| こんばんは。常々、既成概念にとらわれない生き方をしようと思っているけど、それを実践するのはなかなか難しいなと思っているmartinです。`` さて、ppBlogでは現状、大まかに3種類のカレンダーを指定できますが、その内2種類は、TABLEタグを用いたものです。まぁ、よく見るカレンダーの構造を見ると、TABLEタグを使って表みたく作成というのは自然な流れでしょう。web界隈の最前線は追っていないので、ちょっと知るのが遅かった気もしますが、カレンダーの中には、TABLE要素を使わずに、UL要素やOL要素などのリスト要素を用いてカレンダーを生成する試みもあるようです。`` Tableless Calendar In Use `` A Semantic List-Based CSS Calendar ``` 一口にリスト要素を使うといっても、色々な記述があり、紹介しているサイト毎に違っています。で、未だに無視できない数のユーザーの方々がIE6を使っていると思うのですが、少なくとも上記2つのサイトは、IE6で見ると微妙に表示が崩れてしまいます(IE6,7に見られるバグで、hasLayout をもった要素のOL 要素の番号付けが無視されるというものは、有効な解決法がなく致命的)。なので、自分なりに、どのブラウザで見ても同じような見栄えになるようにと色々試した結果、以下のやつが現時点での最適解かなというのに辿りついたので、ppBlogにも採用するついでに紹介しておこうと思います。`` `` TABLE要素の代わりにOL要素(Ordered List)を使います。日付は時系列なものですから、順序付きリストを用いるのが良いでしょう。このテーブルレスカレンダーの特徴として挙げられるのは、ひとつのHTMLの記述で、3種類の全く違った見栄え(ボックス型・水平型・垂直型)にすることが可能ということです。この見栄えの制御には、CSS を使いますが、かなりシンプルな記述で済みます。また、IE6にも対応となると、色々ややこしいCSSハックを駆使しがちですが、CSSハックは全く必要ありません。`` では早速、カレンダーを生成するHTMLソースを見てみましょう。以下のような感じです。``` <div id="calendar">` <ol class="wheader">` <li>S</li>` <li>M</li>` <li>T</li>` <li>W</li>` <li>T</li>` <li>F</li>` <li>S</li>` </ol>` <ol class="weekday">` <li class="blank"> </li>` <li class="blank"> </li>` <li class="blank"> </li>` <li class="daySubmit" title="エイプリルフール">1</li>` <li>2</li>` <li>3</li>` <li class="Sat">4</li>` <li class="Sun">5</li>` <li>6</li>` <li>7</li>` <li>8</li>` <li>9</li>` <li>10</li>` <li class="Sat">11</li>` <li class="Sun">12</li>` <li>13</li>` <li>14</li>` <li>15</li>` <li>16</li>` <li>17</li>` <li class="Sat">18</li>` <li class="Sun">19</li>` <li>20</li>` <li>21</li>` <li>22</li>` <li>23</li>` <li>24</li>` <li class="Sat">25</li>` <li class="Sun">26</li>` <li>27</li>` <li>28</li>` <li class="Holiday" title="みどりの日">29</li>` <li>30</li>` <li class="blank"> </li>` <li class="blank"> </li>` </ol>` </div>`` `` 例として今年4月のカレンダーをあげます。曜日を表す部分(日月火水木金土)と、日にちの部分を分けて、それぞれOL要素でグルーピングしていて、各にwheader とweekday というクラス名を与えています。ppBlogでは、記事を書いた日付には、daySubmit というクラス名が与えられます。`` まず、通常の、よく見るボックスタイプですが、これは以下のようなCSSで実現できます。```#calendar * {` margin: 0; padding: 0; /* まずは、マージンやらのリセット */`}`#calendar ol {` list-style: none; /* 順序付きリストの番号を非表示に */` width: 220px ; /* この横幅指定が一番のポイント */`}`#calendar li {` float: left; /* これもポイント */` border: solid 1px #aaa;` width: 18px; height: 18px;` margin: 2px;` padding: 3px;` text-align: center;` line-height: 18px;` font: 600 14px Trebuchet MS;`}`#calendar ol.wheader li {` background: #c69;` color: snow;`}``/* その他 ppBlog用のオプション */`li.daySubmit { background-color : #feff7d; }`li.Sun { color: red; }`li.Sat { color : blue; }`li.Holiday { color : orange; }`li.Today { font-weight: 900; }`li.blank { border: solid 1px #ddd !important; background: #f5f5f9; } `` ポイントは、OL要素に具体的に横幅を指定して、かつ、LI要素を左寄せにすることです。指定した幅に達すると自動的に下に流れ込みます。となると、水平タイプにするのは簡単で、幅を指定しなければ良いわけです。その際に、曜日の部分や、空白のリスト要素はあえて表示させる必要はないので、以下のような記述になります。```#calendar ol {` width: auto; /* 幅を指定しない! */`}`#calendar ol.wheader, #calendar ol.weekday li.blank {` display: none; /* 非表示に */`} `` 最後に、垂直タイプですが、これも簡単で、従来、OL要素は縦に展開するものです。それを上ふたつではフロート指定で横方向に伸ばしたので、そのフロート指定をしなければ、自ずから縦になります。明示するなら以下のような感じです。```#calendar ol.wheader, #calendar ol.weekday li.blank {` display: none; /* 非表示に */`}`#calendar ol.weekday li {` float: none; /* フロートの解除 */`} `` それでは、実際のデモを見てみましょう。`` [クール/]Tableless Calendarのデモ
`` ボタンをクリックすれば、その場でひとつのカレンダーが3通りに切り替わります(最後にスタイルを適応させないボタンも付けました。OL要素のデフォルトの動作が確認できます)。JavaScriptで制御しているのですが、動的スタイルシートの適応は、`動的スタイルシートの作成 で紹介した手法を用いています。`` 個人的に、このOL要素を用いたカレンダー表示というのは、お気に入りなので、近くバージョンアップ予定のppBlogに組み込んでいます。後、現状、ボックスタイプでは、週の初めは日曜日ですが、これを任意の曜日を指定できようにしています。|martin|1|1|||
[49] => 1235575823|開発日誌|モブログでの画像位置の指定テスト| `フォーラムであがっていたモブログに関してのカスタマイズチェック。例によってモブログが使えない環境にいるので、Gmailから疑似モブログ。``画像を二つ付けてみる。ひとつは、先頭に持って来て、右よりの指定。もうひとつは、記事の最後に持って来てセンタリングの指定。``ちなみに1枚目の写真は、昨年のエッフェル塔。昨年は、フランスがEUの議長国だったので、ブルーカラー。今は従来のオレンジ色に戻っている。`2枚目は、ユーロディズニー。パリ郊外にある。ディズニーランドは日本では行ったことがなかったので、これが初。この日は常に気温零度前後、雪もちらついてものすごく寒かったけど、急降下系のアトラクションは良かった。` |martin|1|1|||
[50] => 1235152352|開発日誌,PHP|UNIXタイムスタンプからハッシュ生成| ppBlogバージョン1.7.7から採用している機能のひとつに、コメント通知のメールからダイレクトでログイン出来てコメント返信できるというのがあります。その際に、リンクのURLに付加する文字列が今いちランダムになっていないので、ちょっとアルゴリズムの見直しをしてみました。時限性を持たせるために、UNIXのタイムスタンプから生成したハッシュをリンクのURLに付加しているのですが、タイムスタンプをチェックしたいので、復元可能なものであることが必要です(一方向で良ければ、sha1関数 を使えば良いけどニーズに合わない)。`` 単純に、UNIXのタイムスタンプをppBlogで用意している暗号化関数my_encrypt() に通すと、タイムスタンプの性質上、最後数桁しか変化せず、それに対応して生成されたハッシュも下数桁しか変化しません。まぁ、これはmy_encrypt()の性能の問題なんですが、この部分はそんな高性能でなくてよいし、過去の資産との互換性も考えると my_encrypt()はいじりたくないです。``$unix_time1 = 1234560000; // 10桁のUNIXタイムスタンプ`$unix_time2 = 1234567890; // 上と下4桁が違うだけ`echo my_encrypt($unix_time1); // 結果は、VwoLV1MOAwhVBg`echo my_encrypt($unix_time2); // 結果は、VwoLV1MOBABcBg ``こんな感じでえらく似通った文字列になる[zzz/] なので、このタイムスタンプを逆順にして更に基数変換すればよいかなと。逆順にすれば、大きく数値が変動します。そこで、文字列を逆順にする関数はないかstr_reverse という関数名で探してみましたがなさそうです。なので、``$unix_time_reverse = join("", array_reverse(preg_split("//", time()))); ``という力技で暫くローカルのテスト環境で動かしていたんですが、いやきっとあるはずだと、もう一度マニュアルを探してみたらありました。``$unix_time_reverse = strrev (time()); ``strrev という名前でしたか・・・。`` 実は、単に逆順にしただけでは、my_encrypt()のアルゴリズムからしてそう大きな変化は望めないので、更に base_convert() 関数を利用して10進数から2進数に変換します。decbin でも行けるかなと思ったんですが、扱える最大の数が10 進数の4294967295とのことで、これは使えない。``$unix_time_binary = base_convert (strrev(time()), 10, 2); // 10進数を2進数に変換 `` これで最初に挙げた例だと、``$encoded1 = my_encrypt(base_convert(strrev("1234560000"), 10, 2));` // 結果は、VwgIUlcJAglUBgEJU1RUUgdRVAk`$encoded2 = my_encrypt(base_convert(strrev("1234567890"), 10, 2));` // 結果は、VwkJU1cIAglVBwEJU1VVUgZRVQgJVgIEVFcGAwhT`$encoded3 = my_encrypt(base_convert(strrev("1235064688"), 10, 2)); // 別の例` // 結果は、VwgIU1YJAwhVBgAJUlRUUgZQVAgIVgMFVVYHAwhSUAdWCQ ``まぁ、最初に比べるとだいぶマシかなと思います。さて、この復元ですが、逆の操作をするだけです。``$decoded = strrev(sprintf ("%010s", base_convert(my_decrypt($encoded1), 2, 10)));` // この場合は、1234560000 を返す ``これで、元の10桁のタイムスタンプを取得できます。ひとつ注意する点は、順序を逆にした文字列を戻す際に、元のタイムスタンプによっては逆順にした文字列の先頭がゼロになる場合があるということです(上の例だと反転した0000654321 は654321 と解釈される)。なので、sprintf 関数を用いて、ゼロで10桁になるように埋め合わせをしておきます。``sprintf("%010s", "654321"); // この結果は、0000654321 `` 実際の実装(?)としては、これらとsha1関数を組み合わせたりして、長い文字列を生成してます。|martin|1|1|||
[51] => 1234967192|開発日誌|モブログの絵文字?|携帯を試せる環境にいないのでGmailから。`[クール/]という文字列を打ったと想定して。`|martin|1|1|||
[52] => 1234925314|開発日誌,JavaScript|動的スタイルシートの作成| こんばんは。だいぶ日も長くなってきましたね。`` さて、小生のブログで、「エクセルデータをHTMLテーブルに変換」というエントリーを書いて、そこでppBlog用に見栄えの良いTABLEを作成してくれるページ を公開していました。早速、使って下さったユーザーの方から、ppBlogをリスト表示にしていると、テーブルのスタイルシートが有効になっていないとのご指摘がありました。確かに、リスト表示での個別スタイルシート指定はすっかり対応を忘れていました。`` というわけで、ppBlogでは記事毎にスタイルシートやJavaScriptを指定することが可能ですが、あまり知られていない気もするので簡単に使い方を書いておきます。スタイルシート(CSS)を指定したければ、記事のどこでも良いので、[style][/style] で囲った中の記述がCSSとして認識されます。記述はまんまCSSと同じです。具体例を挙げると以下のような感じ。``[style]`.article-content table { border-color: tomato; }`[/style] ``とか。.article-content は、記事内容要素に対するクラス名です。記事の個別表示のときは、記事ボックスはひとつしかないので問題ありませんが、複数の記事が表示されている場合、上の例だと、別の記事にテーブルが含まれていたら(クラス名が同じため)そこにも反映されてしまいます。なので、これを回避するには、指定したい記事の固有IDを利用すると良いです。ppBlogでは、すべての記事にUID1234567890 のようなIDが割り振られます。``[style]`#UID1234567890 .article-content table {` border-color: tomato; /* IDを利用して適応先の .article-content を絞り込む */`} `[/style] ``追記 2009/02/19 18:56:29 考えてみると、このUIDを付加する作業は、ppBlogの方で自動的にやるべきかなぁ。次バージョンではそうしようと思います。
`` 記事ごとのJavaScript指定も同じように、[script][/script] で囲った中に記述すればOKです。``[script]`alert("Bonjour, tout le monde!"); /* 普通にJavaScriptを記述 */`[/script] `` 前置きが長くなりましたが、本題。最初に挙げたリンク先 のソースを見れば分かりますが、動的にスタイル指定を適応させる処理を入れています。同じような処理は、ppBlogで使っているソースハイライト表示用のsyntax.js でも使っていますが、ここでは、上記エクセルコピペのテーブル変換の部分を抜粋してみます。```var sheet = d.styleSheets && d.styleSheets[0]; /* 最初のスタイルシートを取得 */``var rulesCSS = { /* JSON形式で要素毎のスタイルを指定 */` 'table' : 'border: solid 1px gray; margin: 2em auto; border-collapse: collapse;',` 'table td' : 'border: solid 1px gray; padding: 2px; text-align: right;',` 'table th' : 'border: solid 1px gray; padding: 2px; text-align: center;',` 'thead tr th' : 'background: #eeffff;',` 'tbody tr th' : 'background: #ffeeee;'`};``for (var el in rulesCSS){` if(sheet.addRule){ /* IE 向け */` sheet.addRule(el, rulesCSS[el]);` } else { /* Firefox, Safari, Opera 向け */` sheet.insertRule(el + '{' + rulesCSS[el] + '}', sheet.cssRules.length);` }`} `` このように、予めJSON配列などに適応させたいCSSを記述している時は、こんな感じで動的に変更させることが出来るのですが、「普通のCSSの記述」つまり``<style type="text/css">` table { border: solid 1px gray; margin: 2em auto; border-collapse: collapse; }` table td { border: solid 1px gray; padding: 2px; text-align: right; }` table th { border: solid 1px gray; padding: 2px; text-align: center; }` thead tr th { background: #eeffff; }` tbody tr th { background: #ffeeee; }`</style> ``を、このまま適応させたいときもあると思います。ppBlogでは、リスト表示モードというのがあり、記事の読み込みにはAjaxを活用しています。この際に、最初の方で紹介した、記事ごとのCSS記述があると、まさにこんな感じで、テキストとしてCSSの記述も読み込みます。で、それを処理するのを忘れていました、という最初の話に戻るのですが、その辺の処理は以下のようにしてみました。lib.jsの256行目あたりからの部分ですが、IEとMozilla系で処理が違うので条件付きコンパイルを使っています。``if(!o("#css4list")){ /* ID#css4list を持つオブジェクトがなければ */` oParts.create("style#css4list", null, o("head")); /* ID名css4listを持つSTYLE要素をHEAD要素の子要素として追加 */` newCSS = o("#css4list").$; /* HTMLStyleElementオブジェクトの取得 */` newCSS.type = "text/css";`} else newCSS = o("#css4list").$;` /*@cc_on @*//*@if(1) newCSS.styeSheet.cssText = css[1]; @else@*/` newCSS.textContent = ""; /* 前に適応させたCSSをクリア */` newCSS.appendChild(d.createTextNode(css[1])); /* 新たにCSSを設定 */`/*@end@*/ `` リストモードでは記事は常にひとつしか表示されないので、ひとつ動的スタイルシート用のHTMLStyleElementを用意しておけば十分です。IEとMozilla系では、そこから先の処理が違います。IEでは、スタイルシートオブジェクトから操作。``HTMLStyleElement.styleSheet.cssText = (先に挙げたような素のCSSテキスト); `` Mozilla系では、DOMオブジェクトとして操作。``HTMLStyleElement.appendChild(document.createTextNode(先に挙げたような素のCSSテキスト)); `` 複数行にわたるCSSテキストを一気に適応させたいときは、こんな感じでしょうか。``ちなみに、[object HTMLStyleElement] から[object CSSStyleSheet] にアクセス?する際もIEとMozilla系では違いますね。IE8では、だいぶ歩み寄りが見られたような気もするけど。```[object HTMLStyleElement].styleSheet = [object CSSStyleSheet] /* IE */`[object HTMLStyleElement].sheet = [object CSSStyleSheet] /* Mozilla */` ``なので上のスクリプトの例では、IEの処理部分は以下のように書いても同じです。```document.styleSheets[document.styleSheets.length - 1].cssText = css[1]; ``つまり``newCSS.styleSheet == document.styleSheets[document.styleSheets.length - 1]; ``まぁこんなとこですかねぇ。そろそろアップデートせねば。。|martin|1|1|||
[53] => 1232585022|開発日誌,JavaScript|IE8βでもVMLを使えるように,IE8-VML| こんばんは。Windows 7βを試用中ですが、写真をお洒落に見せるスクリプト (photoeffect.js)が、IE8βでエラーとなり意図した効果が得られないのを発見。調べてみると、IE8ベータがVMLをサポートしていないのが原因っぽいです。おそらく、正式版ではVMLはサポートされるとは思いますが、確証はないので(Silverlightとかあるし)、現時点での回避策を考えてみました。`` IE8には、3つのレンダリングモードがあり、(紆余曲折ありましたが)デフォルトではフル標準モードでレンダリングされます。じゃ、どんな時にQuirksモード(後方互換[1] の非標準モード)になるかというと、以下の場合です。```
` 文書中に DOCTYPE宣言がない場合 ` 文書型が HTML3.0以下の場合 ` HTML4.0 TransitionalまたはFramesetのDOCTYPE宣言にURLを含まない場合 ` `
``の3つです。詳しくは、SummerWind - IE8のレンダリングモードに関するまとめ あたりを参照。`` 今どきのブログシステムでは、これらに該当しない可能性が高く、IE8は標準モードで動きます。なので(少なくとも現時点では)VMLのスクリプトが動かないわけです。じゃ、どうするか? 簡単そうなのは、[g]METAスイッチ[/g]を使うこと。とりあえずVMLはIE7モードでは問題なく作動するので、以下のようなmetaタグをwebページに追加すれば良いです。``<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /> `` 確かに、これは簡単だし現実的な解決法ですが、こうしちゃうと、JavaScriptもIE7モードになっちゃいます 。IE8では、querySelectorAll などのSelectors APIやらDOMオブジェクトに対するgetter/setter API など、面白そうなAPIがサポートされるのに、IE7モードで走らせると、それらが使えません。`` 出来れば、IE8モードのままでVMLも有効にしたいです。こんなときに使えるのが、インラインフレーム<iframe> 。最近、ちっとも更新されていないのが気がかりな Dean Edwardsのエントリー が参考になります。`` つまり、IE8なページの中で、sandbox化されたIE後方互換の環境を構築し、その中でVMLを走らせるわけです。実際のデモを見たほうが早いと思うので、IE8βでアクセスしてみて下さい。IE7でも動きます。`` → http://p2b.jp/demo/vml-IE8.html`` IE8やIE7では、どう見えるかイメージショットも載せておきます。`` `` ここでは、単に画像を出力させるVMLを、以下のように関数化しています。```function vmlImg(src, w, h, r){` /*` @src: 画像ファイルを指定 ` @ w: 表示させる横幅` @ h: 縦幅` @ r: 回転角度(オプション)、-360~360` */` var ifr = document.createElement("iframe");` ifr.marginWidth= "0"; ifr.marginHeight= "0";` ifr.scrolling = "no"; ifr.frameBorder = "0";` ifr.style.width = w + "px"; ifr.style.height = h + "px";` ` document.body.appendChild(ifr);` var idoc = ifr.contentWindow.document;` idoc.write(""); idoc.close(); // これがないと document.body は null になる` if(idoc.namespaces){` if(!idoc.namespaces.v){` idoc.namespaces.add("v", "urn:schemas-microsoft-com:vml", "#default#VML" );` }` }` idoc.body.style.backgroundColor = document.body.currentStyle.backgroundColor;` var img = idoc.createElement('<v:image src="'+ src +'" />');` var imgcss = img.style;` imgcss.width = w + "px"; imgcss.height = h + "px";` if(r){` imgcss.rotation = r;` ifr.style.width = 2 * w + "px"; ifr.style.height = 2 * h + "px";` }` idoc.body.appendChild(img);`} `` IE8版ではVMLが正式にサポートされるのを期待して、深追いはしません。```
` [1] 言葉の問題なので、本文とは関係ないですが、前方互換なのか後方互換なのか、上位互換なのか下位互換なのか訳わかめ。視点をどこに置くかの差ですし。IE8から見て、IE7以下は過去のものだから、それらに対する互換性ということで、後方互換みたいに使いましたが、何か違うような。まぁ、言いたいことが分かれば良いのかなって。[^] ` ` `
|martin|1|1|||
[54] => 1230980085|開発日誌|BLOCKQUOTE要素とCITE要素をめぐる考察,blockquote-cite|[style]`.article-content h2 {` font-size: 150%; color: #777;` text-align: left;` margin-top: 3em;`}`.article-content ol {` width: 460px; margin: 2em auto;`}`.article-content dl.quote-1 {` width: 360px;` background: #fff;` border: double 4px #2e8b57;` margin: 2em auto;`}`.article-content dl.quote-1 dt {` padding: 6px 0 0 9px;`}`.article-content dl.quote-1 dd {` background: url(theme/basic/Images/quote-left.png) left top no-repeat;`}`.article-content dl.quote-1 blockquote {` color: #484a47;` font: italic 105% "Trebuchet MS", sans-serif;` margin: .7em auto 1em auto;` padding : 1em 20px 1em 50px;` background: url(theme/basic/Images/quote-right.png) 97% bottom no-repeat;`}`.article-content blockquote.css2compat {` background: #f8f8ff;` border: solid 1px #aaa;` width: 420px; margin: 2em auto;` padding: 0 1em 0em 1em;` font: normal 100%/1.7 'メイリオ';`}`.article-content blockquote.css2compat[title]:before {` content: "¥300C" attr(title) "¥300D¥3088¥308A¥629C¥7C8B";` display: block;` padding: 5px;` margin-left: -1em;` color: #556b2f;`}`.article-content blockquote.css2compat[cite]:after {` content: "¥5F15¥7528¥5143¥3A¥20" attr(cite);` display: block;` font-size: 80%;` text-align: right;` color: #777;` margin-top: 1em;`}`.article-content div.ref-section {` font-size: 90%; color: #777;` margin: 5em 0 3em 0;` padding-top: 3em;` background: url(theme/basic/Images/divider.png) 50% top no-repeat;`}`.article-content div.ref-section ul li {` background-image: none;` margin-top: 1em; `}`.article-content dl.links dt {` background: url(theme/basic/Images/dlmark.png) no-repeat left 9px;` padding-left: 15px;`}`.article-content dl.links dd {` padding-left: 20px; margin-top: -10px;`}`[/style]`` 大晦日に書いていた記事ですが、なかなか時間が取れずこんな時季になりました。瑞祥新春(ずいしょうしんしゅん) 2009。今年もよろしくお願いします。`` とりあえず、以下の点について、現時点での考えを自分なりに纏めてみました。``` BLOCKQUOTE要素とCITE要素のグループ化 ` CSSによるCITE属性やTITLE属性抽出の問題点 ` 引用ブックマークレットの活用 ` 参考リンク ` ``1. BLOCKQUOTE要素とCITE要素のグループ化 `` 昔から、BLOCKQUOTE要素とCITE要素をどう扱うかについては悩ましい問題です(個人的に)。さて、いきなりですが、ここで簡単なクイズをば。XHTML1.0 Strictの仕様に則ると仮定して、考えてみて下さい。``Q. 以下のXHTML文法の間違いを指摘せよ。 ``<blockquote` cite="http://martin.p2b.jp/200812-stream-of-life.html"` title="いのちの流れ">` 日夜 私の血管を流れる 同じ命の流れが` この世界を流れ 旋律に合わせて踊る`</blockquote>` `` 一見すると、BLOCKQUOTE 要素に用いられるCITE 属性(validなURIのみ可)も適切ですし、TITLE 属性も付いてます(これらは必須ではありませんが)。問題は、その引用文です。単なるテキストですが、ブロック要素の直下には、インラインであるテキストは置くことが出来ません。なので、ここは、```<blockquote` cite="http://martin.p2b.jp/200812-stream-of-life.html"` title="いのちの流れ">` <p> 日夜 私の血管を流れる 同じ命の流れが` この世界を流れ 旋律に合わせて踊る</p> `</blockquote>` ``とP要素などのブロックレベルでテキストを囲む必要があります。では、次はどうでしょうか。```<blockquote` cite="http://martin.p2b.jp/200812-stream-of-life.html"` title="いのちの流れ">`<p>日夜 私の血管を流れる 同じ命の流れが` この世界を流れ 旋律に合わせて踊る</p>`<cite>` <a href="http://martin.p2b.jp/200812-stream-of-life.html">` 「生命潮流」より抜粋` </a>`</cite>`</blockquote>` `` 現時点で、CITE属性に与えられたリンクを適切に処理するブラウザはないようなので(ケータイ除く)、読み手に分かりやすいように、CITE要素 を使って、リンクを用意しました。先ず、ここで問題となるのが、BLOCKQUOTE要素の中にCITE要素を含めて良いのか? ですが、これは後で考えるとして、少なくとも、文法エラーではありません。問題は、CITE要素(≠属性)です。CITE要素はインラインレベルなので、これも、最初と同じように、P要素などで囲ってやる必要があります。CITE属性とCITE要素とは、全く別ものであることに留意して下さい。 ```<blockquote` cite="http://martin.p2b.jp/200812-stream-of-life.html"` title="いのちの流れ">`<p>日夜 私の血管を流れる 同じ命の流れが` この世界を流れ 旋律に合わせて踊る</p>`<p> <cite>` <a href="http://martin.p2b.jp/200812-stream-of-life.html">` 「生命潮流」` </a>`</cite>より抜粋</p> `</blockquote>` `` では、先ほど述べた、BLOCKQUOTE要素の中のCITE要素の扱いですが、色んな意見があるようです。神崎氏は、「引用の方法」についてのセクションで次のように述べています。```「引用の方法 」より抜粋 ```出典を示すcite要素の位置は、文法的には特に定められていません。ただし、この例のようにblockquote要素内で引用元を示すと、引用部分をコピー/ペーストする、あるいはスクリプトで引用部分を抽出するといった操作を行う時に、出典が不明にならないというメリットがあります。逆にcite要素を外に置くと、引用部分(blockquote)と出典を直接結びつける方法はなく、プログラムはその関係を単純に理解することはできません。要素をどこにおくべきか判断に迷う時は、どうやって利用されるのかを想像してみると、答えが出てくることがあります。
` ` `引用元: The Web KANZAKI: 強調,引用,グループ化,画像などの要素 ` ``神崎氏は、この実例として、以下のような引用を例示しています。``` <p>次に、文学作品を引用する。</p> <blockquote> <p>吾輩は猫である。名前はまだない。…</p> <p><cite>夏目漱石『吾輩は猫である』</cite></p> </blockquote> <p>この引用文を読んで、次の設問に答えなさい etc...</p>
` 引用元: 強調,引用,グループ化,画像などの要素 -- ごく簡単なHTMLの説明 ` `` 確かに、この場合は BLOCKQUOTE要素の属性であるCITE属性は使えません。出典がWeb上のリソースではないからです。[1] しかしながら、W3C の定義によれば、BLOCKQUOTE要素は、(ブロックレベルの)引用のために準備されたもの であって、それ以上の解釈をしないという立場に立てば、BLOCKQUOTE要素の中に、引用への参照を表すCITE要素を含めるのは、何となく落ち着きません。この辺りは、もはや各人の好みの問題ですし、どちらでも良い気もしますが、個人的にはBLOCKQUOTE要素の外にCITE要素を置きたい派です。その際に、神崎氏が懸念しているような 引用部分(blockquote)と出典を直接結びつける方法 を考慮するならば、BLOCKQUOTE要素とCITE要素をひとつのまとまりと見立てるために、更に外側からブロックレベルの要素でラップするというアイデアは悪くないと考えます。正に、神崎氏が同じページで述べている「グループ化 」をする訳です。DIV要素を使えば、上記『吾輩は猫である』 は以下のように書けるでしょう。```<p>次に、文学作品を引用する。</p>`<div class="quote"> /* 引用に関するセクションのグループ化 */`<blockquote>` <p>吾輩は猫である。名前はまだない。</p>`</blockquote>`<p><cite>夏目漱石『吾輩は猫である』</cite></p>`</div> /* グループ化の終わり */`<p>この引用文を読んで、次の設問に答えなさい etc...</p>` `` このグループ化の概念をもう少し推し進めて、定義型リストのDL要素 を用いたグループ化を考えてみます。例えば、上の例は、以下のような感じになります。```/* DL要素を用いたグループ化 その1 */`<dl class="quote">`<dd> ` <blockquote>` <p>吾輩は猫である。名前はまだない。</p>` </blockquote>`</dd> `<dt> <cite>夏目漱石『吾輩は猫である』</cite></dt> `</dl>` `` 引用文と、その参照元のセットを、一種の定義型リストと解釈するわけです。定義型リストは、通常は、項目と内容の2つの部分から成り立ち、DT要素に定義する語句を、DD要素にはその語句の説明を記述します。しかしながら、DL要素は、使い方が柔軟で、DD要素あるいはDT要素のいずれか1つ以上を含めばよく、DDとDTの順番は問いません。また、DD要素ひとつに対して、複数のDT要素を含めても良いです。DT要素はインラインレベルの要素のみを含むことが出来て、DD要素は子要素として、ブロックレベルの要素のみを許可します。 なので、DD要素の中にBLOCKQUOTE要素が来るのは、何ら問題ありません。上の例では、DT要素がDD要素の後ろに来ていますが、勿論、よく見かけるような形式—DT先行型が好みであれば、以下のような記述になるでしょう。```/* DL要素を用いたグループ化 その2 */`<dl class="quote">`<dt> <cite>夏目漱石『吾輩は猫である』</cite>より抜粋</dt> `<dd> ` <blockquote>` <p>吾輩は猫である。名前はまだない。</p>` </blockquote>`</dd> `</dl>` `` 上記例では、引用元は書籍ですが、web上のリソースからの引用であれば、例えば、最初の例を使うと以下のような感じです。読み手に分かりやすいように、DT要素を2箇所で使っています。```<dl class="quote">`<dt>「<cite>いのちの流れ</cite>」より抜粋</dt>`<dd><blockquote` cite="http://martin.p2b.jp/200812-stream-of-life.html"` title="生命潮流">`<p>日夜 私の血管を流れる 同じ命の流れが` この世界を流れ 旋律に合わせて踊る</p>`</blockquote></dd>`<dt class="cite">` 引用元: <a href="http://martin.p2b.jp/200812-stream-of-life.html">` PPBLOG: 生命潮流` </a>`</dt>`</dl>` `` 後は、見栄えを良くするために、これらDL要素などの振る舞いをスタイルシートで指定すればOKです。実際のサンプルは以下。```「いのちの流れ 」より抜粋 ``日夜 私の血管を流れる 同じ命の流れが `この世界を流れ 旋律に合わせて踊る
` `` 引用元: ` PPBLOG: 生命潮流` ` ` `` グループ化している点でHTMLパーサーにも分かりやすく(多分)、また読み手にとっても分かりやすいと思います。また、グループ化のメリットとして、スタイルシートでのデザインが容易くなることが挙げられます。このサイトで使っているBLOCKQUOTEに対するスタイルシートは、以下のようになっています(テーマBasicの場合)。```dl.quote {` width: 86%;` background: #fffafa;` border: solid 1px #aaa;` margin: 2em auto; padding: 0;`}`dl.quote dt{ padding: 5px 0 0px 10px;}`dl.quote dt cite { font-weight: 600; color: #556b2f; }`blockquote {` font: 103%/1.7 "メイリオ", "Trebuchet MS", sans-serif;` color: #484a47;` margin: 0px auto;` padding: 15px 15px 15px 48px;` background: url(Images/quote.png) -5px -5px no-repeat; /* 引用の画像を左上に */`} `` ここでは、BLOCKQUOTE要素の背景に、引用符の画像を固定させていますが、DL要素の背景に、左上の引用符の画像を指定して、BLOCKQUOTE要素の右下にも引用符画像を用意すると以下のような感じになります。````ロマ書 5章3-5節 より ```[...] More than that, we rejoice in our sufferings, knowing that suffering produces endurance,`and endurance produces character,`and character produces hope, and hope does not disappoint us, [...]`
` ` ` `` これに対するスタイルシートは、以下のような感じです。```dl.quote {` width: 360px;` background: #fff;` border: double 4px #2e8b57;` margin: 2em auto;`}`dl.quote dt {` padding: 6px 0 0 9px;`}`dl.quote dd {` background: url(Images/quote-left.png) left top no-repeat;`}`dl.quote blockquote {` color: #484a47;` font: italic 105% "Trebuchet MS", sans-serif;` margin: .7em auto 1em auto;` padding : 1em 20px 1em 50px;` background: url(Images/quote-right.png) 97% bottom no-repeat;`} `` この指定では、右下の引用符画像が、BLOCKQUOTEのサイズに応じて、適切な位置に納まるのがポイントでしょうか。これを、グループ化せずに、BLOCKQUOTE要素のみで実現しようとすると、そう簡単には行かないのではないかと思います。[2] ``2. CSSによるCITE属性やTITLE属性抽出の問題点 `` さて、これまで、BLOCKQUOTE要素とCITE要素のグループ化およびそのメリットについて述べてきました。中には、BLOCKQUOTE要素のCITE属性があるのに、わざわざCITE要素も持ち出して冗長だと感じる方もいるでしょう。しかしながら、前述したように、CITE要素とCITE属性は全く別物です。でも、時々、その中身がほぼ同じという時もあるでしょう。そういう場合は、後述するCSSの指定で、比較的簡単にCITE属性やTITLE属性を抜き出して、読み手に「見せる」ことが可能です。以下に実例を挙げます(IE6,7以外のブラウザでしか意図したように振る舞いません)。```日夜 私の血管を流れる 同じ命の流れが `この世界を流れ 旋律に合わせて踊る
` `` IE6,7ユーザーの方に、Firefox3.0.5でのスクリーンショットを載せておきます。`` `` 引用符の画像があって若干見づらいですが、ポイントはそこではなくて、「生命潮流」やら引用元のURIが表示されていることです。IE6,7ユーザー以外の方は、表示されているURL文字列をマウスで選択してみて下さい。このHTMLソースは以下のようです。```<blockquote class="css2compat"` cite="http://martin.p2b.jp/200812-stream-of-life.html"` title="生命潮流">`<p>日夜 私の血管を流れる 同じ命の流れが<br />`この世界を流れ 旋律に合わせて踊る</p>`</blockquote> `` BLOCKQUOTE要素のみです。これ以上ないぐらいシンプルですね。これに対するスタイルシートは以下。```blockquote.css2compat {` background: #f8f8ff;` border: solid 1px #aaa;` width: 420px; margin: 2em auto;` padding: 0 1em 0em 1em;` font: normal 100%/1.7 'メイリオ';`}`blockquote.css2compat[title]:before {` content: "¥300C" attr(title) "¥300D¥3088¥308A¥629C¥7C8B";` display: block;` padding: 5px;` margin-left: -1em;` color: #556b2f;`}`blockquote.css2compat[cite]:after {` content: "¥5F15¥7528¥5143¥3A¥20" attr(cite);` display: block;` font-size: 80%;` text-align: right;` color: #777;` margin-top: 1em;`} `` CSS2.1での:before、:after疑似要素を使って、CITE属性やTITLE属性を抜き出しています。CSS3ならコロン(:)が2つ連続します。モダンなブラウザならダブルコロン(::)でも問題なく作動しますが、IE8βが対応していません(コロン1個なら対応)。なかなか簡単に実装できて便利そうです。しかしながら、問題点が2つあって、ひとつは、ブラウザ最大シェアのIE6,7が未対応なこと。もうひとつは、Operaユーザー以外はそうでしょうが、折角、引用元のURIが表示されているのに、マウスでクリックすることも文字列を選択することも出来ないのです! [3] contentの文字列は、文字化けを避けるため、16進数の数値文字参照にしています。多分、日本語のままでも大丈夫でしょうけど。CSSの数値文字変換については、「参考リンク 」のセクションにあるサイト(使えない文字)で行いました。`` URIが表示されているのに、それをクリックしてリンクすることも出来ず、それならばと文字列を選択しようにもそれすら出来ない現状では、読み手にやさしい実装とは言えません。何より、IE6,7では全く役に立ちませんし。これならば、JavaScriptで、BLOCKQUOTE要素のCITE属性やTITLE属性を読み出して、リンク表示させた方が読み手には都合が良いでしょう。そういうスクリプトは沢山見つかるでしょうし、ppBlogでも簡単に実装はできます。`` というわけで、この手法はネタとしては魅力的ですが、個人的には、あまりオススメできないかなと思います。``3. 引用ブックマークレットの活用 `` そろそろ疲れてきたので、まとめようと思います。読み手にも、(おそらく)解析マシンにも優しい手法として、BLOCKQUOTE要素(+CITE属性)とCITE要素のグループ化が、個人的には、現時点での最適解かなと思います。ただ、このアプローチの弱点は、記述量が増えることです。只のテキストなので、データ量としては大したことはありませんが、ブログなど文章の書き手にとっては、なかなか見過ごせない問題です。そこで、こういうときの引用ブックマークレット。この手の引用ブックマークレットは探せば、いくらでもあると思いますが、自分なりに作成してみました。Firefoxでしか確認してません。他のブラウザ向けに調整が必要かも。`` 使い方は、簡単で引用したいwebページの引用箇所を、マウスで選択した状態で、このブックマークレットを発動させると、DL要素でグループ化した状態で、テキストエリアが表示されるので、それをCtrl+Cなどでコピーして「Close」ボタンを押せばOKです。後は、それをブログ作成のテキストエリアなどに貼り付ければ良いわけです。``[quoteIt]
``Firefoxなどでは、上記リンクを、ブラウザのリンクバーまでドラッグ&ドロップすれば、そのままブックマークとして登録されます。また、登録しなくても、この記事の適当な部分を選択して上記リンクをクリックすれば、実際にどんな感じか試すことが出来ます。タグを含んだソースなどもコピペ出来るように考慮しています。リンクとかもそのまま有効になるようにしようかなと思いましたが、実際問題としてそこまでの機能は不要かなと思い、それは実装していません。JavaScriptの勉強としては面白そうですが。```4. 参考リンク `` 以下、参考になるリンクを挙げておきます。`` PC Tips > 引用に關する覺書/HTMLの定義のための覺書 ` よくまとまっています
`` 永井俊哉ドットコム > XHTMLでの引用方法 ` とても参考になります
`` 夢幻の棺 > HTMLにおける引用 ` よくまとまっています
`` sitepoint > Blockquote: Then and Now ` [g]Microformat[/g]のcite-relなどの言及あり、興味深いです。コメントでのやりとりも参考になる。
`` 使えない文字 ` 記事で紹介したCSSのcontent文字列のCSS数値参照で使いました。ほかにも、HTML実体参照だとか、JavaScriptで日本語文字列をUnicode展開出来たり何かと便利なサイト。
` ``|martin|1|1|||
[55] => 1229606221|開発日誌|更新PINGサーバーの一覧を更新,latest-ping-server| こんにちは。皆さん、ブログを書いた際に、その更新情報を更新pingサーバーに送っていると思いますが、たくさん存在していたpingサーバーも盛衰があるようです。ppBlogの初期設定のままでは、少々古いping情報もあるので、2008年末時点で安定していると思われる最新の更新pingサーバーをまとめてみました。`[style]`.article-content table { margin: 1.5em auto; width: 500px; border: solid 1px #333; border-collapse: collapse;}`.article-content table td {text-align: left; padding: 2px; border: solid 1px #444;}`.article-content table td:nth-child(odd) { background:#eeeeff;}`.article-content h3 {text-align: left; font-size: 160%; border-left: 10pt solid #69c;}`[/style]`` Pingサーバー Ping送信先アドレス ` ` BlogPeople ` http://www.blogpeople.net/ping/ ` ` ` Google ブログ検索 ` http://blogsearch.google.co.jp/ping/RPC2 ` ` ` Yahoo! ブログ検索 ` http://api.my.yahoo.co.jp/RPC2 ` ` ` Technorati ` http://rpc.technorati.jp/rpc/ping ` ` ` はてなRSS ` http://r.hatena.ne.jp/rpc ` ` ` ドリコムRSS ` http://ping.rss.drecom.jp/ ` ` ` PING.BLOGGERS.JP ` http://ping.bloggers.jp/rpc/ ` ` ` fc2ブログ ` http://ping.fc2.com/ ` ` ` Ask.jpブログ検索 ` http://ping.ask.jp/xmlrpc.m ` ` ` Weblogs.com ` http://rpc.weblogs.com/RPC2 ` ` ` livedoor Reader ` http://rpc.reader.livedoor.com/ping ` ` ` gooブロッグ ` http://blog.goo.ne.jp/XMLRPC ` `
`` また、これに合わせて、更新サーバー設定のスクリプトもアップデートしました。重複した更新サーバーをチェックするようにしたりとか。添付のping.inc.php はmodules ディレクトリに、xmlrpc.php は、index.phpと同じディレクトリにアップすればOKです。`` 尚、ppBlogでは、更新pingサーバーは、管理画面の「環境設定」→「更新サーバーの管理」からいくらでも追加できます。テキストエリアに特定の書式で貼り付ければ良いのですが、使いやすいように、以下にコピペ用を用意しました。これをテキストエリアに貼り付けて、更新ボタンを押せばOKです。なお、ping.inc.php をアップデートしてから、追加するのを強くお勧めします。古いままだと、重複して登録してしまうので。その際は、直接、ownerディレクトリにあるping.ini.php を編集しないといけません。``ppBlogコピペ用 ``BlogPeople|www.blogpeople.net/ping/|www.blogpeople.net/newblog.html`Google ブログ検索|blogsearch.google.co.jp/ping/RPC2|blogsearch.google.co.jp`Yahoo! ブログ検索|api.my.yahoo.co.jp/RPC2|`Technorati|rpc.technorati.jp/rpc/ping|technorati.jp/`はてなRSS|r.hatena.ne.jp/rpc|d.hatena.ne.jp/`ドリコムRSS|ping.rss.drecom.jp/|`PING.BLOGGERS.JP|ping.bloggers.jp/rpc/|ping.bloggers.jp/`fc2ブログ|ping.fc2.com/|`Ask.jp ブログ検索|ping.ask.jp/xmlrpc.m|`Weblogs.com|rpc.weblogs.com/RPC2|www.weblogs.com/`livedoor Reader|rpc.reader.livedoor.com/ping|reader.livedoor.com/`gooブロッグ|blog.goo.ne.jp/XMLRPC|blog.goo.ne.jp/index.php?fid=freshEntry `[file:1229606221_xmlrpc.php:3.1/]`[file:1229606221_ping.inc.php:8.1/]|martin|1|1|||
[56] => 1228249176|開発日誌,PHP|マルチバイトを考慮したstr_replace関数,mb_str_replace| こんばんは。最近、めっきり寒くなってきました。ラボは基本的に中央暖房なんですが、古いせいか壊れていて温度計は14度ぐらい。冷え症の身には応えます。`` さて、ユーザーの方から、パスワードやIDを変更したタイミングでログが壊れるという報告がありました。こちらでは再現出来なかったんですが、調べたところ、ログの書き換えにマルチバイトに対応していないstr_replace関数を使っているのが原因かと思いますので、マルチバイトに対応したやつを考えてみました。PHPには、マルチバイトに対応した色んな関数が揃っている のですが、頻用するstr_replaceのマルチバイト版mb_str_replace が(何故か)ありません。オンラインのPHPマニュアルには、ユーザー寄稿のメモが沢山載せてあって、色々と参考になります。この中に、mb_str_replace()があったので、それに若干修正を加えて以下のようなものを用意しました。```/* マルチバイトを考慮したstr_replace */`function my_str_replace($search, $replace, $target, $encoding = ENCODE){` $notArray = !is_array($target) ? TRUE : FALSE;` $target = $notArray ? array($target) : $target;` $search_len = mb_strlen($search, $encoding);` $replace_len = mb_strlen($replace, $encoding);` foreach ($target as $i => $tar){` $offset = mb_strpos($tar, $search);` while ($offset !== FALSE){` $tar = mb_substr($tar, 0, $offset).$replace.mb_substr($tar, $offset + $search_len);` $offset = mb_strpos($tar, $search, $offset + $replace_len);` }` $target[$i] = $tar;` }` return $notArray ? $target[0] : $target;`} `` これで、str_replace関数と大体似たような挙動をしてくれますが、本家str_replaceと違う点は、引数(ひきすう)の$search や$replace に配列を指定出来ないことです。なので配列に対応した関数を用意しましょう。上記の関数を使います。```/*` str_replace関数のマルチバイト版` 上記 my_str_replace()が必要`*/`function mb_str_replace($search, $replace, $target){` if(is_array($search)){ // $searchが配列なら` if(!is_array($replace)) $replace = array($replace);` foreach ($search as $i => $needle){` $rep = isset($replace[$i]) ? $replace[$i] : $replace[0];` $target = my_str_replace($needle, $rep, $target);` }` return $target;` } else return my_str_replace($search, $replace, $target); // $searchが配列でないとき`} ``これを使ったサンプルをば。全角空白を□(四角)に、「空白」という文字を「四角」に置換します。``$target = " おか機 ←全角空白です。";`$search = array(' ', '空白');`$replace = array('□', '四角');`$result = mb_str_replace($search, $replace, $target);``var_dump($result); // これで結果を出力 ``これの結果は、以下の通り。パフォーマンスもそんなに悪くないと思います。``string(39) "□おか機□←全角四角です。" ``これの修正を施したutils_admin.php の最新版を添付しておきます。replace_log_by_target()関数界隈が変わっています。``[file:1228249176_utilsadmin.php:37/]|martin|1|1|||
[57] => 1220030180|開発日誌|ppBlog向けテーマチェッカー| こんにちは、martinです。ずっと前から、作らんとね-と思っていて、なかなか作らずにいたテーマチェッカーを作成してみました。ただし、バージョン1.7.6 向けなので、クラス名とか変更されている部分もあります。`` ちなみにv1.7.6はまだリリースすらされていません。来週あたりでしょうか。とりあえず、チェックする点を挙げておくと、``` ppBlogで必須のスタイルシートのクラス名をチェック。指定がない場合はピックアップ。 ` 同様に、各テーマディレクトリにあるべき必須の画像もチェック。 ` ppBlogには必須でないが、各テーマで指定している独自のクラス名を抽出。使っていない冗長なクラス指定を見つけやすく。 ` `` どういう感じの出力になるかは、以下のリンクで確認出来ます。このサイトのテーマ:3paneをチェックした結果です。`` →http://p2b.jp/demo/checker-result.html`` なかなか悲惨なことになっていますが、足りないところが分かりやすくて良いですね[zzz/]`` これを実際に使用するには、添付のptc.php をブログ本体のindex.php と同じディレクトリにアップして、ブログの方でログインした状態でアクセスすると、使用できます。ppBlogに認識されてるテーマがセレクトボックスに列挙されるので、調べたいテーマを選べば、後は結果が表示されますよ(多分)。``[file:1220030180_ptc.php:16.3/]|martin|1|1|||
[58] => 1219714349|開発日誌|Cooliris(PicLens)用のMedia RSSを出力するモジュール,ppblog-image-gallery-for-cooliris| こんばんは、martinです。フォーラムの方で、画像ギャラリーのデータベースをMedia RSS として出力できれば、Cooliris(formerly PicLens) (クールアイリス?)を活用できますというご指摘があり、面白そうだったので実装してみました。`` かつてPicLensとして知られていたCoolirisですが、これは良いですね。IE6/7やFirefox,Safariといった主要なブラウザにはプラグインとして対応 しています。Coolirisは、スライドショーを実現する外部スクリプトを用意してくれているので、プラグインが入っていないブラウザでも簡単にスライドショーを提供できます。具体的なデモは、小生のブログで見ることができます。` →http://martin.p2b.jp/gallery/
``「Slide show powered by Cooliris 」というリンクがあるので、それをクリックすれば、簡易スライドショーが始まります。もし、Coolirisプラグインがインストール済であれば、そのプラグインが立ち上がります。リッチなスライドショーを体験するために、是非ともプラグインを入れましょう。`` `` さて、ppBlogでの実装ですが、各エントリーに使われているJPEGファイルを画像データベースより抽出し、それを100枚ごとに分割し、Media RSSファイルを作成するようにしています。画像が370枚あれば、4つのMedia RSSファイルがfeedsディレクトリに作られるわけです。Coolirisは、RSSファイルのページリンクを提供しているので、シームレスに、この4つのRSSファイルを読み込み、展開してくれます。`` 具体的な出力は、以下のような感じです(gallery3.rss の場合)。```<?xml version="1.0" encoding="utf-8" standalone="yes"?>`<rss xmlns:media="http://search.yahoo.com/mrss" version="2.0"` xmlns:atom="http://www.w3.org/2005/Atom">`<channel>`<atom:icon>http://martin.p2b.jp/theme/3pane/Images/ImageGallery.png</atom:icon>`<atom:link rel="previous" href="http://martin.p2b.jp/feeds/gallery2.rss" />`<atom:link rel="next" href="http://martin.p2b.jp/feeds/gallery4.rss" />`<generator>ppBlog1.7.5</generator>`<title>ppBlog-generated Image Gallery</title>`<link>http://martin.p2b.jp/</link>`<description>Media RSS for Image Gallery</description> `` ページリンクは、<atom:link rel="previous" や <atom:link rel="next" で出力、また、各テーマディレクトリに、もしImageGallery.png という画像があれば、それをCooliris用のカスタムアイコンと認識して、それようの出力もします。画像の高さは、26px がおススメとのこと。`` これに続いて、各画像の情報がITEM要素として列挙されます。```<item>` <title>Yvetot7-2008/06/25</title>` <link>http://martin.p2b.jp/PIX/1214400950_Yvetot7.jpg</link>` <guid>1214400950_Yvetot7.jpg</guid>` <media:thumbnail url="http://martin.p2b.jp/PIX/s1/1214400950_Yvetot7.jpg" />` <media:content url="http://martin.p2b.jp/PIX/1214400950_Yvetot7.jpg" type="image/jpeg" />`</item> `` ここにあるTITLE要素ですが、ここに日本語が入っていると、Coolirisがその要素を認識してくれないっぽいので英数字に限定しています。簡易スライドショーでは認識してくれるようですが。。`` このモジュールは、次回のアップデートで採用予定ですが、v1.7系使いの方は、試すことが出来ます。添付のadmin.phpを既存のもとの入れ替え(念のためもとのadmin.phpは別名保存しておきましょう)、modulesディレクトリに、新規にmrss.inc.phpをアップロード、またgallery.inc.phpは上書きします(これもバックアップを)。この状態で、「管理画面」→「各種ツール」に「MRSSの作成」というメニューが現れるので、それをクリックすると、最新の画像データベースを元にMedia RSSファイルが作成されます。`` ご指摘・アドバイス等あればお願いします。``[file:1219714349_admin.php:25.7/]`[file:1219714349_gallery.inc.php:4.9/]`[file:1219714349_mrss.inc.php:2.6/]|martin|1|1|||
[59] => 1219172191|開発日誌|しぃペインターとPHPによる画像投稿処理| こんばんは。お絵かきツールの話でも。`` 小生のweblogのアクセス解析の「検索ワード」を見ると、いつも「お絵かきツール」とか「FLASH お絵かき」での訪問がトップにきてます。「Flash版お絵かきツール 」のページがリンクされているんですが、これ2005年6月のエントリーなので、昔日という印象ですが、このFLASH版お絵かきは、この時点から何も変わってません。当時、画像を保存したりするメソッドが分からなくて頓挫したままになってまして。ppBlogに組み込む予定だなんて言ってましたが。。今は、FLASHで作成した画像データを保存したり、呼び出したりする技は知っているので、この古いスクリプトを対応させても良いのですが、元々が中途半端なプログラムなので、凝り出すと時間がかかりそうです。`` で、Web上には、FLASHではありませんが、Java仕様の大変高機能なお絵かきツールがいくつかあるので、それを利用するのが最善であろうと思います。おそらく一番有名なのは、「[g]しぃペインター[/g]」でしょう。このソフトの存在は知っていたんですが、実際にダウンロード(DL)して、中身を読んだことはありませんでした。で、おとといDLして読んでみると、色々設置方法などについて詳しく書かれています。サーバーへのデータの受け渡しの記述もあるので、簡単にPHPと連携できそうです。で、やってみたらあっさりと画像データを取得できたので、簡単なプログラムを書いてみました。自由に投稿できて、最新の9個の画像をギャラリー閲覧出来ます。````Javaのことは全く分かりませんが、しぃペインターのプログラムが、サーバーに画像データを渡してくれるので、それをPHPでキャッチ出来れば良いわけです。しぃペインターの説明が分かりやすく、簡単に実装できました。上のデモのキモの部分を抜き出してみると、```if(!$raw_data = file_get_contents('php://input')){` $raw_data = $HTTP_RAW_POST_DATA; // 次の手段`} `` 基本的には、これがすべてです。php://input は、POSTの生データの読み込みを許可するプロトコルで、これと`file_get_contents関数 とを組み合わせるだけですね。`まずこのやり方でトライして、で、駄目だったら $HTTP_RAW_POST_DATA を見るという流れです。これで、しぃペインターからのデータを無事にゲット出来たら、後は、ごにょごにょデータを弄るだけですね[にこっ/]``しぃペインターのマニュアルによれば、``画像などを投稿した後の返り値にURL:と言う文字が初めにある場合、続く文字列をURLとして読み取ってその指定されたURLへジャンプする機能がつきました。これにより細かい動作をサーバー側が管理する事が容易になります。 ``とのことなので、データの取得に失敗したら、``if(empty($raw_data)){` exit('URL:draw.php?mode=error&due=empty'); // 生データの取得に失敗した場合`} ``みたいな記述で、自由にページを遷移させることができます。うまく生データを取得できた場合以下の処理が続きます。`$img_name = time(); // タイムスタンプをファイル名に`$img_size = substr($raw_data, 9, 8); // ファイルサイズ情報は必ず8バイト`$img_data = substr($raw_data, 19, $img_size); // 以下、画像データ`$img_ext = strstr(substr($img_data, 0, 4), 'PNG') ? '.png' : '.jpg'; // 最初の4文字で拡張子を識別``if($fp = @fopen(IMG_DIR.$img_name.$img_ext, 'wb')){` flock($fp, LOCK_EX); // まぁ、とりあえず` fwrite($fp, $img_data);` fclose($fp);` exit('URL:draw.php?mode=done&aim='.$img_name.$img_ext); // 書き込み成功した後のリンク処理`} else exit('URL:draw.php?mode=error&due=fopen'); // 書き込み失敗! ``` こんなに簡単なら、もっとはやく向き合っていればよかった。。|martin|1|1|||
[60] => 1218749667|開発日誌,JavaScript|チェックボックスを一度に複数選択したい,shiftKey-event|[script]`o(d).on("click", function(){` var tar = oParts.evt.target;` if(tar.nodeName.toLowerCase() == "input" && tar.type.toLowerCase() == "checkbox"){` var tr = tar.parentNode.parentNode;` if(tar.checked == false){` tr.style.backgroundColor = (tr.rowIndex % 2 == 0) ? "#eff1f3" : "#fff";` } else tr.style.backgroundColor = "highlight";` if(oParts.evt.shiftKey){` var i = tr.rowIndex - 1, item, cb = o("td > input[type=checkbox]");` for(i; i > 0; i--){` item = cb.item(i).$;` if(item.checked == true) break;` item.checked = true; ` item.parentNode.parentNode.style.backgroundColor = "highlight";` }` }` }` })`function resetAll(){` o("td > input[type=checkbox]").each(function(e, i){` if(e.checked){` e.checked = false;` e.parentNode.parentNode.style.backgroundColor = (i % 2 == 0) ? "#eff1f3" : "#fff";` }` });`}`function setAll(){` o("td > input[type=checkbox]").each(function(e){` e.checked = true;` e.parentNode.parentNode.style.backgroundColor = "highlight";` });`}`[/script]` こんばんは。イベントに関するJavaScriptの話をば。`` ppBlogでは、管理画面で記事の削除やコメントの削除が出来ますが、現状、ひとつずつしか削除できません。削除したいものが沢山あるときは大変なので(あまりそういう機会はないと思うけれど)、次回アップデート版では、チェックボックスでチェックした複数の記事などを1度に削除出来るようにする予定です。実際のスクリーンショットは以下。`` `` チェックボックスをチェックする操作というのは、数が少ない内は良いけど、数が多くなるとマウスで逐一クリックしていくのが億劫になります。なので、シフトキー(SHIFT )を活用できるようにします。つまり、最初の方のチェックボックスをチェックしておいて、シフトキーを押した状態で、下の方のチェックボックスをクリックすると、その間のチェックボックスも自動的にチェックされた状態になるというものです。この手のインターフェイスはよく使われていて、例えば、Gメールでも、そういう操作が可能です。以下に実際のデモを載せておきます(下のデモはスクリーンショットじゃなくて、ちゃんと操作できますよ)。```` さて、この手のことを実装するには、シフトキー(SHIFT )が押された状態というのをJavaScriptで検知する必要があります。最初は、```var shift, e = oParts.evt, k = e.keyCode ? e.keyCode : e.which;`shift = e.shiftKey ? e.shiftKey : (k == 16 ? true : false);`if(shift){ // シフトキーが押されていれば` ``なんてのを思いつきましたが、キーボードイベントは、以前の知識しかないなぁ、と思って、新しい情報をwebで探してみました。したら、えらく新しいのがありました(今年七夕の記事です[にこっ/])。`` JavaScript Madness: Keyboard Events `` もはや、event.which なんてのは不要で、event.keyCode でこと足りるんですね。しかも、どのブラウザでも、event.shiftKey を認識してくれそうです。なので、最終的には、この部分は、```if(oParts.evt.shiftKey){ // シフトキーが押されていれば ``と非常に短く記述することが出来ますね。ppBlog向けの、上に上げたデモのソースコードを載せておきます。```o(document).on("click", function(){ // Event delegation` var tar = oParts.evt.target; ` if(tar.nodeName.toLowerCase() == "input" && tar.type.toLowerCase() == "checkbox"){` var tr = tar.parentNode.parentNode;` if(tar.checked == false){` tr.style.backgroundColor = (tr.rowIndex % 2 == 0) ? "#eff1f3" : "#fff";` } else tr.style.backgroundColor = "highlight";` if(oParts.evt.shiftKey){` var i = tr.rowIndex - 1, item, cb = o("td > input[type=checkbox]");` for(i; i > 0; i--){` item = cb.item(i).$;` if(item.checked == true) break;` item.checked = true; ` item.parentNode.parentNode.style.backgroundColor = "highlight";` }` }` }` });``function resetAll(){ // すべてのチェックボックスを解除する` o("td > input[type=checkbox]").each(function(e, i){` if(e.checked){` e.checked = false;` e.parentNode.parentNode.style.backgroundColor = (i % 2 == 0) ? "#eff1f3" : "#fff";` }` });`}``function setAll(){ // すべて選択する` o("td > input[type=checkbox]").each(function(e){` e.checked = true;` e.parentNode.parentNode.style.backgroundColor = "highlight";` });`}` `` ppBlogでは、多くのマウスイベント処理がありますが、ほとんどは[g]Event Delegation[/g]を 活用しています。上のデモでも、チェックボックス1つひとつにイベントを登録していくのではなくて、クリックされた要素がチェックボックスであれば・・・、という捉え方をしています。イベントは、バブリング(伝達)していくものなので、最上位要素でモニターして、そのターゲットさえ掴めれば良いというわけです。`` Event Delegation versus Event Handling ` |martin|1|1|||
[61] => 1217936560|開発日誌|Gメールからのリッチテキストは?|リッチテキストの太文字 ですよ。
カ ラ フ ル 文 字 です。
`
引用文はどうかね。 リスト形式をみてみる。
ゴールドバッハの予想 リーマン予想 コラッツの問題 ゲーデルの不完全性定理 第1不完全性定理 第2不完全性定理 ふむふむ。
|martin|1|1|||
[62] => 1217935485|開発日誌|Gメールからのモブログテスト| ケータイからのモブログは、ここフランスでは、よく調べていないので現状無理だけど、`モブログでの挙動を調べる必要があったので、Gメールをケータイに見立てて、モブログ`のテスト。自動投稿モードです。`` ファイルを添付という形で、画像も付けておくか。|martin|1|1|||
[63] => 1217725184|開発日誌|ソーシャルブックマークでの被リンク数を取得する最新APIまとめ,social-bookmark-count-api|[style]`dl dt a {font-size: 125%; color: #033; font-weight: bold;}`dl dd.uri { color: #603;}`dl dd.counter {color: #393;}`dl dd.counter b{ font-weight: bold; color:#360;}`[/style]` こんばんは。ppBlogでは、代表的なソーシャルブックマーク(SBM)の被リンク数を記事ごとに表示できる機能が付いていますが、いくつか古いAPIを用いていて、きちんとブックマーク数が取得出来ていないものもありました。なので最新のものを調べたのでメモがてら。`` ppBlogで初めから用意しているSBMは、はてなブックマーク 、del.icio.us 、livedoorクリップ 、Buzzurl (バザール)、Yahoo!ブックマーク の5つです。グーグルも付けてはいますが(登録用のアイコン表示のみ)、グーグルには被リンク数を表示するAPIがないみたいなので、今回はスルーします。`` 以前は、被リンク数を取得するAPIとして、画像での提供のみのところもあったと思いますが、今では、この5つのどれもが[g]JSON形式[/g]あるいはXML形式での情報取得に対応しているので、幾分扱いやすくなっています。個別に見ていきましょう。各々、JSON(XML)へのリンクおよびカウンター値の形式を挙げています。カウンターの値は、正規表現などを用いて簡単に取り出せます。``` ♥はてなブックマーク ` http://b.hatena.ne.jp/entry/json/?url=(エンコードしたURL) ` JSONでのカウンター取得値:"count":"(¥d+)" ` ♥del.icio.us ` http://badges.del.icio.us/feeds/json/url/blogbadge?hash=(md5ハッシュ化したURL ) ` JSONでのカウンター取得値:"total_posts":"(¥d+)" ` ♥livedoorクリップ ` http://api.clip.livedoor.com/json/comments?link=(エンコードしたURL) ` JSONでのカウンター取得値:"total_clip_count":(¥d+), ` ♥Buzzurl(バザール) ` http://api.buzzurl.jp/api/counter/v1/json?url=(エンコードしたURL) ` JSONでのカウンター取得値:"users":(¥d+), ` ♥Yahoo!ブックマーク ` http://num.bookmarks.yahoo.co.jp/yjnostb.php?urls=(エンコードしたURL) ` XMLでのカウンター取得値:ct="(¥d+)" ` `` 補足しておくと、最後のYahooでの指定ではJSONではなく、以下のようなXMLを返します。直接、カウント数を取得することが出来ます。``<?xml version="1.0" encoding="utf-8" ?>`<results>`<SAVE_COUNT u="http%3A%2F%2Fp2b.jp%2Findex.php%3FUID%3D1188848148" ct="6" />`</results> `` 先ほど述べたように、カウント数は、JSON形式や、XML形式で取得できるので、さらにそれをパースして・・・とやっても良いでしょうが、ここはPHPの正規表現のみで簡単に取り出せるので、それで十分でしょう。`` さて、上記で挙げたSBMサービスでは、このようにJSONといった文字列でカウンターを取得できますが、他のSBMサービスによっては、画像カウンターでしか取得できないところもあります。例えば、FC2ブックマーク では、自分の知る限り、画像でのみ被リンク数の取得が可能です。この場合は、どうしたら数字を文字列として取り出せるでしょうか?`` 画像で提供しているところでは、たいてい数字を出力する画像ファイルにリダイレクトさせるという手段を講じているので、このリダイレクト先のURLを知ることが出来れば、文字列として取得可能です。PHPを使いたい場合、どうやるか? FC2を具体例に挙げると、画像カウンター取得URLは以下で与えられます。``http://bookmark.fc2.com/image/users/(取得したいURL) ``まず、最初に考えるのは、とりあえず、PHP組み込み関数のfile_get_contents()関数 を用いて、出力してみること。```<?php`$url = 'http://bookmark.fc2.com/image/users/http://p2b.jp/index.php?UID=1188848148';`echo file_get_contents($url); // とにかく書き出してみる`?> ``結果は、まぁ当たり前ですが、リダイレクトされた後のPNG画像(ヘッダーを正しく出力していないので文字化けするけど)が出力されます。リダイレクト後のURLは、この場合、被リンク数がゼロなので[zzz/]、``http://bookmark.fc2.com/icons/00000.png ``となっています。この00000.png の部分を取り出すことが出来ればよいわけです。PHPには、最初から色々便利な関数が準備されているので、それを利用します。ここでは、stream_get_meta_data() 関数を使いましょう。この関数を使うことで、まずサーバーが返す情報配列を得ることができて、それを解析すれば、リダイレクト先の情報もゲットできます。この場合は、以下のような配列を返します(一部Xの文字で情報を隠しています)。```Array`(` [wrapper_data] => Array` (` [0] => HTTP/1.1 302 Found /* 多くのクライアントは、このステータスコードをリダイレクトと解釈する */ ` [1] => Date: Sun, 03 Aug 2008 00:19:03 GMT` [2] => Server: XXXXXXXXXXXXXXXXXXXXXXXXXX` [3] => X-Powered-By: XXXXXXXXXXXXX` [4] => Set-Cookie: CAKEPHP=XXXXXXXXXXXXXXXXXXXXX; path=/` [5] => P3P: CP="XXXXXXXXXXXXXX"` [6] => Location: http://bookmark.fc2.com/icons/00000.png /* リダイレクト先 */ ` [7] => Content-Length: 0` [8] => Connection: close` [9] => Content-Type: text/html` [10] => Content-Language: en` [11] => HTTP/1.1 200 OK` [12] => Date: Sun, 03 Aug 2008 00:19:03 GMT` [13] => Server: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` [14] => Last-Modified: Fri, 25 Aug 2006 09:03:28 GMT` [15] => ETag: "XXXXXXXXXXXXXX"` [16] => Accept-Ranges: bytes` [17] => Content-Length: 90` [18] => Connection: close` [19] => Content-Type: image/png` [20] => Content-Language: en` )`` [wrapper_type] => http` [stream_type] => tcp_socket` [mode] => r+` [unread_bytes] => 90` [seekable] => ` [uri] => http://bookmark.fc2.com/image/users/http://p2b.jp/index.php?UID=1188848148` [timed_out] => ` [blocked] => 1` [eof] => `)`` ``wrapper_data というキーの値が更に配列になっていて、その中のLocation: という文字列がある行を探し出せばOKです。具体的には以下のような記述になるでしょう。```$url = 'http://bookmark.fc2.com/image/users/http://p2b.jp/index.php?UID=1188848148';``if($fp = @fopen($url, 'r')){` $meta = stream_get_meta_data($fp);` foreach($meta['wrapper_data'] as $r) {` if(substr(strtolower($r), 0, 9) == 'location:') {` $count = preg_replace('{^.+/(¥d+)¥.(?:png|gif)$}', '¥¥1', $r); /* 画像カウンタはほぼPNGかGIFファイル */` break;` }` }` $count = sprintf('%d', "$count");`} else $count = 0; `` 最新版のutils.phpでは、この画像カウントのものは採用していませんが、この記述を組み込めば、画像カウンターからの取得も可能ですね。`` 一応、これを反映させた最新版のutils.phpを添付しておきます。1895行目からのsocialBookmark()関数の中身が変わっています。`[file:1217725184_utils.php:85.6/]|martin|1|1|||
[64] => 1217081338|開発日誌,JavaScript|Google Adsenseの表示タイミングを制御する| 日本を出る前後、昨年の9月頃から、このページでグーグルのAdsenseを利用しています。使いこなしていないせいか、広告収入が100$に達するのに、あと数年はかかりそうなペースです。さて、この広告表示は、JavaScriptのdocument.write を使ってインラインフレーム(IFRAME)で書き出すということをしています。前回のエントリーで使用しているBLOCKQUOTE のボーダー枠を演出するJavaScriptの実行タイミングが遅いなと感じていたんですが、原因は、このdocument.writeの存在でした。ちょうど2年前に、これに関するエントリー (document.write()の実行タイミングをずらす方法 )を書いていたのを思い出し、早速、このサイトにも適用させてみました。`` 効果はてきめんで、先にBLOCKQUOTE の装飾が終わり、その後、Google Adsenseが表示されるようになりました。ppBlogでは、DOMの構築が終わるタイミングで実行されるJavaScriptが多いので(これはドキュメントの読み込み完了前に実行される)、document.write()に起因する描画遅延対策は大切ですね。`` 具体的に行った対処法は、シンプルです。テーマのtemplate.php を弄ります。このサイトのベーシックなテーマでは、左側のカラム(サイドバー)にGoogle Adsense用のDIVタグ(IDはgoogle-ads)を用意してます。```<div id="google-ads">` /* この中にグーグルからの広告用javascriptを貼り付けている */`</div><!--#google_ads--> ``で、この中身を以下のようにします。既存のグーグルのコードをいじることはないです。``<div id="google-ads">` <script type="text/javascript">` (function (){` var alts = [];` d._write = d.write; /* オリジナルのdocument.writeをコピーしておく */` d.write = function(s){ alts.push(s);}; /* 新たにdocument.writeを定義。ここでは、単に配列に入れるだけ */` oParts.start(function(){ /* DOM構築完了のタイミングで実行されるように登録する */` o("#google-ads").html(alts.join("")); /* 配列に入れた本来のdocument.writeの中身を書き出す */` d.write = d._write; /* オリジナルのdocument.writeに戻す */` });` })();` </script>` /* 以下、既存のコード */` <script type="text/javascript"><!--` google_ad_client = "pub-XXXXXXXXXXXX";` google_ad_slot = "XXXXXXXX";` google_ad_width = 180; /* 広告の幅 */` google_ad_height = 150; /* 広告の高さ */` //--></script>` <script type="text/javascript"` src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>` </div><!--#google_ads--> `` 基本的には、これでOKです。後は、予め広告のサイズが分かっているので、見栄えとしてCSSファイルを少しいじるだけです。このサイトでは以下のように指定しています。``#google-ads { ` margin: 70px auto 0 10px;` padding: 0;` width: 180px; /* 広告の幅に合わせる */` height: 150px; /* 上と同様に */`} `` ちなみに、このサイトのwebRing は、「ページ作成機能」を使って作っていますが、表示スクリプトはBlogPeopleさん のを利用しています。ここでもdocument.writeが使われているので、それに対処した記述をしています。その中身をさらしておきます。```<div class="center" style="color:#2f4f4f;">`<h2>ppBlog's webRing</h2>`<p style="padding:1em;font-size:14px;width:300px;margin:auto;">`ppBlog使いの方々です。随時募集中。`<br />多分に見落としなどもあると思いますので,このサイトもお願いしますというのがあれば`気兼ねにメール下さい。自薦他薦問いません。</p>`<div id="_webRing" style="margin: 2em auto;width:300px;text-align:left;"></div>` /* ここから */`<script type="text/javascript">` (function (){` var alts = [];` d._write = d.write;` d.write = function(s){ alts.push(s);}` oParts.start(function(){` o("#_webRing").html(alts.join("")); /* 上で用意した DIV#_webRing に流し込む */` d.write = d._write;` });` })();`</script>` /* ここまでがポイント */`<script type="text/javascript" charset="utf-8"` src="http://www.blogpeople.net/display/usr/0f0d40535b5b4103.js"></script>`</div> |martin|1|1|||
[65] => 1217017559|開発日誌|アクセス解析の「リンク元」をすっきりさせたい| 以前、ユーザーの方からのコメントで以下のような要望がありました。```2.アクセス解析の「リンク元」統計へのURL置換機能の実装 `私が使っていたことのあるアクセス解析サービスにあった機能なのですが……`どういう機能かというと、登録してある文字列を含むアドレスを一つのリンク元として扱うようなものです。例えばgoogle.co.jpと登録しておけば、グーグルからのアクセスを全部まとめて何件、と表示します。`というのも、検索エンジンからのアクセス自体は別項目で詳しく見れますし、「リンク元」項目では逆に検索エンジンからのアドレス文字列が大量に羅列しているため一般サイトなどからのアクセスが判別しにくいという現状がありまして要望させていただきました。 `` これは、ごもっともな意見であるので、実装してみました。従来の「リンク元」の画面が、少し変わって、ドメインの部分がクリック出来るようになっています。クリックすると、ドメインをまとめたいか?と訊ねてくるので、「OK」ボタンを押すと、選んだドメインはまとめて集計するようになります。こうやって、いくらでもドメイン毎にまとめることが可能です。現状、登録のみで削除とかは、直接設定ファイル(stat/data/replace.ini.php )を弄るしかありませんが、まぁこれで良いかなと思います。``` `` これを使って、このサイトのリンク元の主要なドメインを纏(まと)めてみました。検索エンジンのドメインがひとくくりに集計されるので、それ以外のマイナーなサイトからのリンクが見つけやすくなりました。``` `` これを適用するためのファイルを添付しておきます。なお、従来のアクセス解析画面では、ページの一番下に[AdminTop] とか[BlogTop] とか付いていて、正直、使い辛いなと思ったので(インターフェイスも洗練されていない)、アイコン化して、ページの左上に固定表示させました(IE6にも対応 )。そのためのアイコンやらCSSファイルも同梱してます。アイコンは、stat/icon ディレクトリに入れて下さい。view.php , stat.css は既存のものを上書き(いずれもstat ディレクトリの中です)して下さい。ppBlogのバージョンは、最新でなくても1.6系以上(1.5系も?)であれば大丈夫だと思います。念のため、元のview.php は保持しておくのがベターですが。`` ご指摘があれば、どうぞ。「登録したら、もはやリンク表示にしなくていいんじゃない?」 とか。←2008-07-26 03:02:56 そうしました。``[file:1217017559_new-stat.zip:12.5/]|martin|1|1|||
[66] => 1216950144|開発日誌|記事編集時に表示しているページに簡単にアクセスしたい| こんばんは。この週末は時間が取れそうなので、マイナーアップデートを予定しています。さて、自分のブログを書いていて、不便に思ったところを改善してみたのでメモ。`` この旅日記 のようにページ数が10ページとかなると、記事の編集時には、テキストエリアが縦にずらっと10個並ぶわけです。で、修正したいページのテキストエリアにたどり着くのに、ちょっと間を取られるので、(ログインモードで表示される)編集アイコンをクリックしたら、直接、表示しているページのテキストエリアにフォーカスが行き、かつ、その他のテキストエリアは、縮めた状態で表示させるようにしてみました。修正は、jsファイルのみで済みます。`` 記事の各ページはAjaxを利用して、該当ページの部分のみ動的に読み込んでいるので、ログイン中に記事タイトルの右横に表示される編集アイコン のリンクは、最初のページのままで変わりません。なので、記事ページを読み込んだタイミングで、この編集アイコンのリンクも書き換えるようにします。これはlib.js のloadPage()をいじります。簡単でして、```if(o('a[href*=edit]', ownerDiv)){` o('a[href*=edit]', ownerDiv).each(function(a){a.href = (a.href.replace(/&?page=¥d+$/, '') + "&page=" + page);});`} ``というのを追加するだけです。やってることは、記事DIV要素の中で、リンク先にeditを含むA要素を探し出して(これは2つあります)、それぞれのリンクhrefに表示しているページを追加してあげる、という単純なものです。`` 次に、editor.js の方をいじります。この中のInitEditor()関数の最後の方に、以下のやつを追加。```var targetPage = /page=(¥d+)$/.exec(location.href);`if(targetPage){` o('textarea[id^=Page]').each(function(page, index){` if(index + 1 == targetPage[1]){` resizeTextArea(page);` ed = page; ed.focus(); o('#Page'+targetPage[1]+'Tab').view(1);` } else o(page).css('height: 20px;');` });`} ``やってることは、記事編集画面でのリンク先がpage=3 とかで終わっていたら、該当する3番目のテキストエリアのみを適切な縦幅で表示させて(フォーカスも合わせる)、他のテキストエリアは縦幅20ピクセルに縮めておく、ということです。`` 尚、各テキストエリアの高さは、それぞれのリサイズバーをマウスでドラッグすることで自由に変えることが出来ますが、昔のマックのウィンドウシェード(MacOSXでも残っているのかな?)みたいに、ダブルクリックでトグルさせるようにするには、やはりInitEditor()関数の中に、次の記述を追加します。```o('.textareaHandler').on('dblclick', function(){` var tar = oParts.target().sib(-1); /* リサイズバーのひとつ前の要素、つまりテキストエリア要素を取得 */` if(tar.css('height') == 20) resizeTextArea(tar.$); else tar.css('height: 20px');`}); `` 自分でいじりながら、JSファイルの修正だけで実現できたのは、ちょっと意外だったり[ウィンク/] この修正を施したjsファイルを添付しておきます。特に問題がなければ、次回アップデートに反映されるでしょう。`[file:1216950144_editor.js:33.5/]`[file:1216950144_lib.js:21.4/]|martin|1|1|||
[67] => 1215347219|開発日誌|オンタイム投稿のテスト| どうでしょうか。どういう仕様が(開発するのに)一番楽チンかなぁとアレコレ考えて、一応の形になったので。「日付の修正」で、未来の投稿したい時間に設定すると、その時間を過ぎるまではドラフト投稿扱いになる。更新pingがどうなるかはこれから見てみる。`` 画像の添付は?` `` 更新PINGのテスト|martin|1|1|||
[68] => 1210823006|開発日誌|ppBlogのお試しサイト| こんにちは。静的リンク出力を取り入れたのがバージョン1.7からで、今1.7.3ですが、だいぶ安定してきた感じなのでデモサイトを設置してみました。`` http://p2b.jp/demo/ppBlog173/index.php`` そのまま何の制限もなしに設置したいというのが本音ですが、さすがにそれだとセキュリティーの問題などありそうなので、一部機能制限を設けています。テーマテンプレートやCSSの編集が不可など。ただ、記事の投稿・編集などは出来るようにしています。更新PINGやトラックバックは不可にしてますが。管理画面にはadmin, passで入ることが出来ます。不具合なども見つかりやすくなるかなと。|martin|1|1|||
[69] => 1210751410|開発日誌|MHTファイルからのログ復元| こんにちは、martinです。掲示板の方で、MHT形式のファイルからログが復元できないだろうかと要望があり、これは出来るべきであろうと思いますので、とりあえず作ってみました。MHT形式からのログ復元は、原理的に100%というわけには行きませんが、なるべく元のログを再現するようにしたつもりです。`` MHTファイルを作成したブログで作動させるのが原則です。使い方は、``` index.phpがあるディレクトリにこのファイルをアップします。 ` 次に、同じディレクトリにmht ディレクトリを作成(FTPソフトで)、パーミッションを707 にします ` index.phpかadmin.phpでログインした状態 で、このmht2log.php にアクセスします ` `` すると、ファイルアップロードの画面になるので、ここで手元にあるMHT形式のファイル(もちろんppBlogが作成したものです)を指定して「変換」ボタンを押せば、作成したmhtディレクトリにアップした月のログが作成されます。例えば、200805.mhtであれば、200805.logというログファイルが作成されます。これは、そのままppBlogのlogディレクトリに流し込むことが可能です。`` 出力されるログの文字エンコードは、UTF-8 かEUC-JP か選べます。入力元のMHTファイルのエンコードはUTF-8でもEUC-JPでもどちらでも構いません。`` そう使う機会はないかもしれませんが(出来れば皆無がベスト)、何かの拍子にログが壊れてしまったけどMHT形式のバックアップログがある場合などに有効かと思います。バージョン1.6.4が生成するMHTファイルを参考に作ったので、古いバージョンで作成されたMHTファイルではうまく動かないかもしれませんが、その時はお知らせ下さい。`[file:1210751410_mht2log.php:5.5/]|martin|1|1|||
[70] => 1209888535|開発日誌,JavaScript|window.onloadの代替スクリプトその2,events-order| 以前に、[g]window.onloadの代替スクリプト[/g]の記事を書いていたんですが、今はちょっと違ったスクリプトになっているので、この辺で、まとめもかねてメモを。`` 今ではどのJavaScrptライブラリーも、画像も含めたページ読み込み完了まで待って、つまりwindow.onloadのタイミングで初期化関数を走らせるなんてことはせずに、もっと早い段階、つまりブラウザがDOMの構造を把握してパースしたタイミングを見計らって、初期化関数を実行するようにしています。Firefox、Operaでは、ブラウザ側がDOMContentLoaded というイベントハンドラを用意してくれているので、これを使います。Safariがこれを採用するのも時間の問題だろな、と前々から思っていたんですが、昨日、Safari最新版(3.1.1)も対応しているっぽいことに気が付きました。こういうスクリプト を書いて、イベントの発火順序を調べていたんですが、何気にSafariで動いているんでちょっとビックリしました。`` イベントの発火順序を調べる→http://p2b.jp/demo/events-order.php`` IEに関しては、DOMContentLoaded というイベントハンドラはないので、以前から色々なアプローチが取られてましたが、今ではbase2 のDean Edwardsも、jquery のJohn ResigもDiego Periniが見つけたdoScroll を採用しています。確かに、これでも良いのですが、自分は天の邪鬼なので、HTCファイルでondocumentready を監視するというアプローチにしています。上に挙げたイベントの発火順序を調べるページの結果を見ると、IEに関しては、次のようなイベント順位で実行されてます。``` oncontentready /* この時点でDOMのパースが終了 */ ` deferred script /* defer指定された外部スクリプトが実行される */ ` ondocumentready /* 次にHTCでのこのイベント。oParts.jsではこの時点で初期化。*/ ` doScroll /* 次にdoScroll */ ` window.onload /* 最後にこれ */ ` `` このサイトのように、ソースをハイライト表示するスクリプトなどを使ってる場合は、数ミリ秒でも早くハイライト関数を起動させたいので、ondocumentreadyのタイミングで実行させてます。doScrollのタイミングでも良いんですが、十数ミリ秒程度遅れるんですよねぇ。oncontentreadyが一番早いですが、極々まれにこれが評価されないことがあるので、確実なondocumentreadyにしてます。`ondocumentready とかoncontentready ってBehavior絡みでしか使えないのが玉に瑕です。普通のイベントハンドラとして使えるようにしてくれれば良いのに、マイクロソフトさん。`` というわけで、ppBlogで使っているJSライブラリ oParts.js での初期化関数は以下のような感じになってます。```oParts.start = function(F){` if(client.Gecko || client.Opera || client.Safari){` document.addEventListener('DOMContentLoaded', F, false);` } else if(client.MSIE){` $IEHTC = document.documentElement.addBehavior('js/ie.htc');` } else o(window).on('load', F);`}; `` SafariでもDOMContentLoadedが使えるようになったので記述が少なくて良いですね。IE向けのie.htcファイルの中身は以下のような感じ。```<public:attach` event="ondocumentready"` onevent="oParts.callee[oParts.callee.length-1]();` document.documentElement.removeBehavior($IEHTC);` $IEHTC=null;" /> `` ちなみにイベント発火順位を調べるスクリプトですが、以下のように指定すると、このサイト以外のページも読み込めます。Yahoo!の例を挙げておきます。``http://p2b.jp/demo/events-order.php?site=yahoo.co.jp`` 余談ですが、jquery-1.2.3 のテストをしていて、気になった点がありました。以下のようなスクリプトを書くと、$()関数がwindow.onloadの後にしか実行されません(IE7の場合)。jqueryに関しては素人なので使い方が間違っているのかもしれませんが、非常に簡単な例なので気になります。```<script type="text/javascript">` window.onload = function(){` document.getElementById("test").innerHTML = '<p>window onloaded!</p>';` }` $(function(){` alert($("#test").html());` });`</script> ``` 実際の実行サンプル 。FirefoxとIE7で挙動が違います。Firefoxでは意図したように、window.onloadよりも先に$()が評価され、<p>original</p> とアラート表示されますが、IE7ではなぜか、window.onloadに割り当てた関数が先に実行されて、<p>window onloaded!</p> って表示されるんですよねぇ。何でかなぁ。doScroll絡み?|martin|1|1|||
[71] => 1208716869|開発日誌|アップロード出来る画像のサイズ| 3MB超の画像をアップしてみます。(注 )元の画像サイズが大きいので、回線が貧弱だと、クリックして元の画像を表示させるのに時間がかかります。` `` アップロードするのに、こちらの回線では2分弱かかりました。`` 昨年の9月末に、アップできる画像の上限を可変的に扱うスクリプトを書いてたはずでしたが、これがローカルのテスト環境でのutils_admin.php や配布版にも反映されてませんで。ローカルの別のテスト環境のディレクトリにあるutils_admin.phpにその記述を見つけました。具体的には、サムネイル画像を生成するcreate_thumbnail()関数内にその記述がありますが、動的に、アップされた画像ファイル処理に必要なメモリを取得して、一時的にサーバーのメモリ容量を増やす方法です。PHP.NETのユーザーメモにあったものです。たった数行の記述を加えるだけですが、これでかなりのサイズの画像ファイルをアップロードすることが出来ます。デジカメが高解像度になって、写真1枚のファイルサイズが1MBを超えるものが当たり前になってるので、ブログの方もこれに合わせないとですね。`` ` ` ` ` `` ちなみに加えたコードは以下のようなやつです。`` $fudgeFactor = 1.7;` $memoryNeeded = round(($info[0] * $info[1] * $info['bits'] * $info['channels'] / 8 + Pow(2, 16)) * $fudgeFactor);` $memoryLimit = 8 * 1048576;` if(memory_get_usage() + $memoryNeeded > $memoryLimit){` $newLimit = ceil((memory_get_usage() + $memoryNeeded) / 1048576);` ini_set('memory_limit', $newLimit.'M'); /* 新しく取得したメモリ量を割り当てる */` } ```追 記 `` いつからかそうだったのか知りませんが、Vista Sp1のIE7上で、いつの間にか写真をお洒落に見せるスクリプトのphotoeffect.js が動いてないのを今日発見しました。VML関係のセキュリティーアップデートで動かなくなったのか理由は定かではありませんが、色々試した結果、``<v:image src="" /> で画像を呼び込むのはダメで、<v:rect><v:imagedata src="" /></v:rect> だと上手く行くようです。なので、久しぶりにphotoeffect.jsもアップデート。ついでに、この効果を施した画像には、photo-canvas というクラス名を付けるようにしました。これで、スタイルシートで、これに対する画像の説明(キャプション)にCSSを適用することが出来ます。```.photo-canvas div.photo-caption { margin: -20px 5px 30px 5px; } ```みたいに。|martin|1|1|||
[72] => 1207571829|開発日誌,JavaScript|pettieSyntaxの微調整とか| こんばんは、martinです。JavaScript単体で稼働するソースハイライト表示用のスクリプトpettieSyntax.js ですが、スタイルシートのクラス指定に対応したバージョン(pettieSyntax-class.js )も作成してみました。と、同時に正規表現の微調整をしています。一応、CSSソースのハイライトにも対応していますが、CSS3のセレクタ とかは何でもありの状態なので、まぁ抜けがあったりするかも知れませんが、そこまで完璧を求めていないので。ちなみに、CSS3のセレクタは、具体例で挙げると以下のような感じです。``a[rel="external"] { /* REL属性がexternalなら外部アイコンの背景を付ける */` padding-right: 5px;` background: url(Images/external-icon.png) no-repeat right center;` }`p[class~="foo"] { /* クラス名にfooが含まれていれば */` margin: 0;` padding: 0;`}`a[href$=".pdf"] { /* リンク名が.pdfで終わっていれば */` background: url(Images/pdf.png) no-repeat right center;`}`a[hreflang|="en"] { /* リンク要素のhreflang属性がenで始まっていれば(enとかen-USとか) */` background: url(Images/english.png) no-repeat right top;`}`div p:nth-child(2n+1) { /* DIVの子孫P要素で奇数番目のもの */` background: ivory;`} `` 別件ですが、JavaScriptライブラリのoParts.js は、このCSS3のセレクタにも対応していて、例えば、``o('div:nth-child(2n+1)') ``とすれば、奇数番目にあるDIV要素を一気に取得することが出来ます。お遊びですが、```<button onclick="o('ul li:nth-child(2n+1)').css('background:red');">`CLICK ME!`</button> ```というコードを記述してみます。期待するのは、「UL要素の子孫のLI要素で奇数番目のやつの背景を赤にする 」という動作です。````CLICK ME!`
``` syntax.jsの最新版とクラス対応版、およびそのCSSファイルを添付しておきます。ハイライト用のCSSファイルは、テーマのCSSファイルに追加しても良いでしょうし、以下のようにCSSファイルの中で呼び出すことも出来ます。``@import 'syntax.css'; `` メンテナンスしやすいのは、上記のように別ファイルで用意しておくインポート方式でしょうか。``[file:1207571829_syntax.js:2.9/]`[file:1207571829_syntax-class.js:2.8/]`[file:1207571829_syntax.css:0.3/]|martin|1|1|||
[73] => 1207470856|開発日誌,JavaScript|pettieSyntaxがCSSに対応| ソースをJavaScriptでハイライト表示するpettieSyntax ですが、CSSの表記にも対応しました。このせいでファイルサイズが3キロ弱になりましたが、まぁこの辺で落ち着くでしょう。`` 色の指定をソースの上の方で、指定できるようにしてます。ソースを見ると、CSSの表記に対応した色指定だけ3色ありますが、これは1.タグ 、2.CSSプロパティー (fontなど)、3.その実際の指定値 に対応しています。```var cssprops = ['indigo', 'slategray', 'indianred', /((?:[-#a-z0-9.,_* +:¥r¥n[¥]=]{2,}|[abipq*]))¥s*¥{¥s*[^}=]+?¥}/ig]; `` 実際のデモとして、このサイトのベーシックテーマに適用しているPREタグのCSS指定をば。```pre {` font: 500 1em/1.4 "Consolas","Bitstream Vera Sans Mono","Lucida Console","Courier New",Verdana,Meiryo,monospace;` background: #f6f6f9;` border: double 4px #808080;` border-width: 0 0 0 4px;` margin: 1em auto;` padding: 20px;` width: 89%;` height: 3em;` color: #333;` clear: both;` white-space: pre;` overflow-x: auto;` letter-spacing: 0.1px;`}`body[id=weblog] pre { /* IE6以外のモダンなブラウザ用 */` overflow: auto;` height: auto;`}` `` こんな感じです。仕様上、PHPやJavaScript用キーワードの中途半端な対応と違って、CSSのあらゆるプロパティーに対応してると思います。最新版を添付しておきます。`[file:1207470856_syntax.js:2.9/]|martin|1|1|||
[74] => 1207282359|開発日誌,JavaScript|ソースコード表示用の軽いスクリプト:pettieSyntax,pettie_syntax| こんにちは。たまにはアップデート以外の記事も書きたいので。`` 前々から思っていたのですが、このブログではPHPとかJavaScriptのソースを提示することがままあります。現状、モノクロの味気ないソースコードだったので、PHPマニュアルのユーザーノート にあるようなカラフルな色付けにしたいなと思っていたわけです。この手のことを実現するには大きく2通りのアプローチがあって、サーバー側でハイライト表示の処理をして読み込ませる方法と、もうひとつはクライアント側のJavaScriptに解析させてその場でハイライト表示させる方法です。前者の例だと、PHPライブラリではGeSHi - Generic Syntax Highlighter などがあり、後者だとグーグルのgoogle-code-prettify が有名でしょうか。`` でも、この手のやつって、これようのCSSファイルも用意しないといけないし、ファイルサイズはでかいし、設置が面倒そうだなと。なので書いてみました。基本的に、自分用なのでPHPとJavaScriptの一部の関数しかサポートしていませんが、まぁ、要は見栄えを良くすることが目的なので、すべてを網羅する必要はないと考えてます。PHPの組み込み関数なんて山ほどありますし。おかげで随分とサイズが小さいスクリプトになりましたが、それっぽく見えます。`` 特徴としては、このスクリプト単体で動作可能 ということです。他の見栄えのためのCSSファイルとかは必要ないです。記事の中のPREタグを見つけたら、その中身をハイライト表示します。初めは、PREタグに特定のクラス名を付けて、それを認識させようかと思っていましたが、そうすると過去の記事の書き換えをしないといけないし、どうせPREタグに書くのはソースコードぐらいだろうと割り切り、PREタグに絞りました。早速ですが、そのソースコードをこのスクリプトを使って表示してみます。``/*` Lightweight syntax-analyzing script` Copyright: modified BSD license 2008 martin` version: 20080803.204553`*/``function pettieSyntax(){` var cssprops = ['#c03', '#003366', '#636', /((?:[^{;_<]{2,}|[abipq*]))¥s*?¥{(¥s*[^}=_[¥]?<>]+?)¥}/ig];` var etcetera = ['#c33', /( > | < )/g];` var operants = ['green', /(¥/¥/¥-¥->|¥+¥+|¥-¥-|!?===?|<=|>=|=>|¥+=|¥-=|!=|&&|¥|¥|| = )/g];` var variants = ['#669', /(¥$¥w+?¥b|var¥b¥w+¥b|@)/g];` var htmltags = ['navy', /(<¥/¥w+?>|<¥w+|<¥?(?:xml|php)|(?:¥?|¥/)>|>)/g];` var keywords = ['blue', /(¥b(?:alert|[Aa]rray|break|case|catch|class|charset|continue|Date|default|define|delete|do|else|false|FALSE|for|function|global|i[fn]|instanceof|new|null|Object|return|script|src|type|switch|this|throw|document¥S|TRUE|true|echo|try|typeof|var|void|while|window¥S|with|Location|version|encoding)¥b)/g];` var decimals = ['#c69', /([¥s:¥/¥(,[+;."=>])(¥-?¥d+(?:¥.¥d+)?)(%|px|pt|em)?/g];` var equipped = ['#036', /([¥.¥s(@>])([^'"¥(¥n=¥s<>¥/]+?)([¥( ])/g];` var oneliner = ['#906', /('[^'¥r¥n]+?'|"[^"]*?"|<![^¥r¥n]+?¥-¥-.*?>)/g];` var regulars = ['tomato', /([¥s(])(¥/[^¥r¥n]+?¥/)([igmy¥s¥);.])/g];` var enoparts = ['indigo', /(¥b(?:o|oParts)¥b|¥.(?:away|moveTo|sizeTo|dimension|target)¥(¥)|¥.(?:loadScript|evt|metrics|start|css|view|each|sib))/g];` var comments = ['#093', /([^:]|)((?:¥/¥/|#)¥s+[^'¥r¥n]+(?:¥r?¥n?|$)|¥/¥*[¥s¥S]+?¥*¥/)/g];` var omitspan = function(m){ return m.replace(/<span[^>]*?>/ig, '').replace(/<¥/span>/ig, '');}` var targets = document.getElementsByTagName('PRE');` if(targets){` for(var t, i = 0; t = targets[i++];){` var c = t.innerHTML.replace(/<(?:span|code)[^>]*?>([^<]+?)<¥/(?:span|code)>/ig, '$1').replace(/¥t/g, '').replace(/'/g, ''').replace(/"/g, '"');` if(/<(?:a |img )/i.test(c)) continue;` c = c.replace(cssprops[3], function(A, B, C){ return /:/.test(C) ? '<span style=¥tcolor:'+cssprops[0]+'¥t>'+B+'</span>' + A.replace(B, '').replace(/([^:{]+?):([^;]+?);/g, '<span style=¥tcolor:'+cssprops[1]+'¥t>$1</span>:<span style=¥tcolor:'+cssprops[2]+'¥t>$2</span>;') : A;});` c = c.replace(etcetera[1], '<span style=¥tcolor:'+etcetera[0]+'¥t>$1</span>');` c = c.replace(operants[1], '<span style=¥tcolor:'+operants[0]+'¥t>$1</span>');` c = c.replace(variants[1], '<span style=¥tcolor:'+variants[0]+'¥t>$1</span>');` c = c.replace(htmltags[1], '<span style=¥tcolor:'+htmltags[0]+'¥t>$1</span>');` c = c.replace(keywords[1], '<span style=¥tcolor:'+keywords[0]+';font-weight:bold¥t>$1</span>');` c = c.replace(equipped[1], function (A, B, C, D){return B + '<span style=¥tcolor:'+equipped[0]+'¥t>' + C + '</span>' + D;});` c = c.replace(enoparts[1], '<span style=¥tcolor:'+enoparts[0]+';font-weight:bold;¥t>$1</span>');` c = c.replace(decimals[1], '$1<span style=¥tcolor:'+decimals[0]+'¥t>$2$3</span>');` c = c.replace(regulars[1], function (A, B, C, D){return B + '<span style=¥tcolor:'+regulars[0]+'¥t>' + omitspan(C) + '</span>' + D;});` c = c.replace(oneliner[1], function (A, B){return '<span style=¥tcolor:'+oneliner[0]+'¥t>' + omitspan(B) + '</span>';});` c = c.replace(comments[1], function (A, B, C){return B + '<span style="color:'+comments[0]+'">' + omitspan(C) + '</span>';});` c = c.replace(/¥t/g, '"');` if(/*@cc_on!@*/false){` t.outerHTML = '¥n<pre>' + c + '</pre>¥n'; /* IEの改行対策です */` } else t.innerHTML = c;` };` }`}; ``` ファイルサイズは2キロ前後と小さいです。ppBlogで使うのであれば、とりあえずこのファイルをjsディレクトリ にアップロードして、後は、lib.js の最初の方で、このスクリプトを以下のように呼び出します。``oParts.loadScript('js/syntax.js'); ``次に同じlib.jsの下の方にある、oParts.start 関数内で、このpettieSyntax() を呼び出せばOKです。``if(typeof pettieSyntax != UD) pettieSyntax(); `` コードを見れば分かりますが、ハイライトの色はSPANタグ内でスタイルシート指定してますので、この部分を好きな色に変えれば良いです。あと、強調したいキーワードを追加したいときも、ソース内の該当箇所に追加していけばよいです。`` ppBlog使用前提なら、上のような設置になりますが、純粋に単体で動かしたい場合は、外部スクリプトとして、``<script type="text/javascript" src="path/to/syntax.js"></script> ``みたく読み込ませて、ページ読み込み完了後にpettieSyntax() を呼べば良いです。`` まだろくに動作検証していないのですが、興味がある方はどうぞ。syntax.jsと、あと、ppBlogの設置例としてlib.jsを添付しておきます。```[file:1207282359_syntax.js:2.2/]`[file:1207282359_lib.js:20.7/]|martin|1|1|||
[75] => 1206021488|開発日誌|久しぶりの更新,longtime-nosee| こんばんは。こっちに来て体重が数キロ減りちょっと吃驚したので最近心がけてよく食べるようにしているmartinです。このところ、やたら忙しくppBlogの開発にまるで時間が割けませんでしたが、ちょいと一息おけたので、一気に進めるところまで進めてみました。何とか頭に思い描いていた感じに仕上がってますが、静的リンクの出力を取り入れようとしてからこんなに時間が経つとは。。`` 結果的に、かなりの部分で静的リンク出力に見合ったナビゲーションにすることが出来ましたが、あとちょっと残ってます。まぁ、拘らなければ良いのですが、どうも統一感がないと落ち着かないので。`` 従来の動的なリンク出力と静的リンク出力は、管理画面で簡単に切り替えることが出来ます。この動作を実現させたいがために、utils.php は大幅な書き換えを余儀なくされたんですが、苦心した甲斐があったと思ってます。`` あとは、ブログのページングをデフォルトで付けてみました。これがあると古い記事にも簡単にアクセス出来るので、従来のものにあった「古い順にソート」するという機能はオプション扱いになります(各テーマテンプレートで指定)。`` 現状、日本語で指定したカテゴリーは、独自のエンコード処理をしてリンク表示(英数字指定のカテゴリーはそのまま)していますが、これが任意のアルファベットを指定できるようになれば、だいたいやりたいことは済むかなぁ。`` 1.7.1ベータ版をお使いの方は、記事やコメント・トラックバックなどのログファイルなどを除いて、ほぼ全てのPHPファイルを上書きすれば良いと思います。index.phpもかなり書き換えてます。あ、一番の方法は、新規にアップして、そこに従来のログファイルを流し込むというやり方ですね。`` まだナビが変な部分がありますが、ちょっとお腹が空いたので、とりあえず。|martin|1|1|JavaScript||
[76] => 1202153955|開発日誌|ppBlogの静的出力,static-output| こんばんは。これは、数年前にppBlogを開発し始めて、そう経たないうちに要望として出ていたことなんですが、ppBlogが出力するページの静的化を検討中です。静的化と言っても、実際にHTMLとして生成したファイルをサーバーに置いておくわけではなく、「見かけ上 」静的ファイルがあるように見せるというものです。具体的には、Apacheサーバーで使用可能な[g]mod_rewrite[/g]を使用します。mod_rewriteの設定を.htaccess ファイルとして記述し、サーバー上に置いときます。このやり方では、.htaccessファイルが有効である必要がありますが、多くのレンタルサーバーでは、Apacheの設定をいじれない代わりに、この.htaccessファイルを使用可にしていると思います。`` そもそも、どうして静的化が必要なのか?という話ですが、これは動的ページと静的ページ(1) 一般論 あたりによく纏まっています。要はSEO絡みの問題なのですが、少なくともグーグルに関しては、「動的URLも静的URLと同様に扱う」 ということらしいので、数年前ならいざ知らず、SEO対策として是非とも静的リンクにしたい、というのはちょっぴりout-of-dateなことかもしれません。実は、個人的には検索エンジン対策のための静的化というのはあまり興味がありませんで、じゃなぜ静的化かというと、勿論、そういう要望があるという理由と、あと、個人的にはこっちにウェイトがあるんですが、見た目がすっきりする というのがあります。昨日から本格的にいじりだしたんで、まだどうするか流動的なんですが、一応、個人のブログサイト の方に反映させています。静的化というと何となく拡張子htmlで終わってるというイメージがありますが、SEO的には拡張子のあるなしは関係ないはずです。なので拡張子なしにしていますが(すっきりするので)、これだと何だか落ち着かないという意見もあるでしょうから、その辺は管理画面で指定できるようにします。`` で、静的リンクの指定ですが、現状、2パターン用意してます。ひとつは、記事のタイトルとは別に、予め英数字からなるタイトルを別に指定しておいて、その指定があれば(例えばemmenagementという指定)、``http://martin.p2b.jp/200802-emmenagement ``みたいになるパターン(頭の200802-は自動的に付加されます)と、あとはそういう指定がない場合のパターンで、これは単にUIDがリンクになります。以下のような感じです。``http://martin.p2b.jp/1201100476 `` 最初のパターンでは日付が勝手に付加されますが、これはサーバーへの負荷を減らすのが目的です。これがないと、リクエストの度に、すべてのログを走査して合致するタイトルを探し出す必要がありますが、予め日付が分かればログを決め打ち出来るので。これに関しては、UIDとリンク用記事タイトルの対応表を別に作っておくという手もありますが。まぁ、何となく日付が分かるのも良いかなと、ない方がもっとスッキリしますが。。このあたりは如何様にも出来ます。まだ途中なんで、記事リンクにちゃんと反映されていないとかありますが、まぁそのうち改善されるでしょう。何か要望とかありましたらどうぞ。|martin|1|1|JavaScript||
[77] => 1199423196|開発日誌|敬頌新禧(けいしょうしんき)| 明けましておめでとうございます。長らく更新が途切れていましたが、少しずつ手直しをしてました。初めて海外で新年を迎えたような気もする今日この頃です。正月3が日は休みが取れたので、かなりプログラミング作業が進みました。ここパリは寒いんですが、まだ雪は降らないんですよねぇ。福岡は元旦から初雪だったと聞きましたが。`` さて、ppBlogですが、JavaScriptは大幅な書き換えを遂行しました。細かいところの動作チェックはまだですが、勉強も兼ねてoParts.js という簡単なライブラリを作成して、これをもとに色んな動作を設定しています。オーパーツ.jsという名前を付けましたが、これはppBlogではもとより、o (アルファベットオーの小文字)関数が基本でしたし(他のメジャーなJSライブラリでいう$関数に相当)、o 関数で得られるパーツを操作し、またppBlogに必要な各種パーツを用意したという意味合いも込めてです。オーパーツといえば、あの[w]オーパーツ[/w]を先ず思い出しますが、まぁ関係ないです。好きですけどね。`` あとは、画像タグの出力周りもちょいと変更しました。主にIEのバグ対策のためですが、ドロップシャドウをもう少し綺麗に見せようというのもあります。このドロップシャドウに関して、現時点では、IE6対策はしていないのですがブラウザシェアではまだまだ最大でしょうから、配布版では対策がされていると思います。`` あと、実験的 ですが、コメントのインターフェイスで、スパム対策として、画像認証([w]CAPTCHA[/w])を導入してみました。ひらがなを入力させるのでHIRAPTCHA (ひらぷちゃー)と名付けました。まぁどれくらい効果があるかわかりませんが、単に実装してみたかったという…。`` 現時点では、[g]oParts.js[/g]も[g]HIRAPTCHA[/g]もググっても検索にかからないのが、また良いですね。`` あ、画像タグの話をしたのでサンプルを載せときます。特に切手風などの効果をかけないやつノーマルなやつです。`` ` ` ` ` ` ` ` ` ` |martin|1|1|||
[78] => 1190046144|開発日誌,JavaScript|ppBlogでのgetElementsByClassName|こんばんは、martinです。ソーシャルブックマークへのリンクアイコンを各記事に付けるようにしました。近々配布予定の最新版に採用してます。またJavaScript関連の話をば。`` 愛用しているタブブラウザFirefoxの現行バージョンは2 ですが、バージョン3 からはネイティブでdocument.getElementsByClassName がサポートされる ようです。現時点でこのメソッドをサポートしている主要なブラウザは存在しないので、[g]document.getElementsByClassName[/g]でググれば分かるように、皆さん、色んなgetElementsByClassNameを書いています。ppBlogのJavaScriptのライブラリlib.js でも、この関数(getByClass)は多用しているのですが、この関数は、ページ内のオブジェクトを逐一調べていくループ作業を伴うので、一般的に言って動作に時間がかかります。`` JavaScript使いの間では、常識かと思いますが、この手の操作で一番スピードが速いのは、[g]XPath[/g]を利用するやり方です。[g]jQuery[/g]で有名なJohn Resig氏のブログに、この手の関数のスピード比較記事があります。 ` →http://ejohn.org/blog/getelementsbyclassname-speed-comparison/`` ネイティブサポートのFirefox3が無茶苦茶速いのは当然として、XPathもDOMを解析していく手法よりはずっと高速なのが分かります。IE6,7を除くモダンなブラウザは、このXPathをサポートしているので、ppBlogでもXPathを使うようにしました。以下のような感じです。``document.getElementsByClassName(className, pElement, tagName){` var d = document, nodes = [], item;` try { // XPathをサポートしているならこれを使う ` var xp = d.evaluate(` './/'+(tagName || '*')+'[contains(concat(" ", @class, " "), " '+className+' ")]',` (pElement || d), null, XPathResult.ANY_TYPE, null` );` for (item = xp.iterateNext(); item; item = xp.iterateNext()){` nodes.push(item);` }` } catch(e){ // そうでなければ地道にDOM解析 ` var cls, items = (pElement || d).getElementsByTagName((tagName || '*'));` for(var i = 0, l = items.length; i < l; i++){` item = items[i];` if(item.className){` cls = item.className.split(/¥s+/);` for(var j = 0, k = cls.length; j < k; j++){` if(cls[j]==className){` nodes[nodes.length] = item; break;` }` }` }` }` }` return nodes.length > 0 ? nodes : null;`} `` John Resig氏のブログにあるのと同じ実験 をしてみましたが(パクっただけ)、彼のサイトにある、Prototype.jsのXPathを使ったもの(xpath.html )と同等か少し速いくらいですね。`` 当然ながら、XPathをサポートしていないIE6,7は、通常通りDOM解析をするアプローチしかないです。こちらの計測では、XPathを利用するより5倍ほど遅いです。`` ちなみに、1つ前のエントリで紹介したphotoeffect.jsも、この関数を使用しているので更新しました。ついでに添付しておきますね。このphotoeffect.jsは、単体で動くので、ppBlog以外の各種ブログでも外部ファイルとして呼び込むだけで簡単に使えます。要望があれば、詳しいクラス指定などの解説書きますんで、その時はたずねて下さい。`[file:1190046144_photoeffect.js:4.9/]|martin|1|1|JavaScript||
[79] => 1188848148|開発日誌,JavaScript|アップした写真をお洒落に見せるJavaScript| 久しぶりのJavaScriptネタです。最近は、マック(MBP)で作業することも多いのですが、アップルの提供する.Mac というサービスを使うと簡単に見栄えのよいホームページ(HP)を作成することが出来ます。このサービスはマックを使ってこそ活きるものですが。`` で、何種類ものHP向けのテンプレートが予め用意してあるんですが、多くのテンプレには、デジカメで撮った写真を単に貼り付けるだけでなくて、それらをちょこっと斜めにしたり切手風に縁取りしたり出来て、お洒落に演出できるわけです。自分も以前からこういうことをppBlogでしたいなぁとは思っていて、現状、写真っぽく見せたりドロップシャドウを付けたりというのはスタイルシートを使って出来るようにしています。後は、切手風とか写真を少し傾けて貼り付けるとかですが、これらはサーバーサイドのPHPプログラムで画像を加工すれば可能なんだけど、写真をアップする際の手間が増えるのは好ましくないし、何よりプログラムを書かないといけない。`` 画像の回転(写真を傾けて貼り付けたいので)なんて、クライアント側のJavaScriptで出来れば楽チンだけど無理だよなぁと思っていたんだけど、実は<canvas> を使えば簡単に出来ちゃうんですね。しかも画像同士を合わせることも簡単に出来る。これなら自分がやりたいことはJavaScriptで出来るじゃないか、ということで書いてみました。`` `` これは通常の、ppBlogでデフォルトで出来ることです。つまり写真のように白枠を付けて、ドロップシャドウを付けて、ということですが、さすがに写真をちょいと傾けるとかは出来ません。ところが、これに、canvasを利用したJavaScriptをかますと以下のようになります。`` `` この写真は上の写真と同じ画像ファイルを指定していますが、見栄えが随分と違ってます。しかもこれをJavaScriptでやっているわけで、canvas恐るべしですね。反対向きの傾きにしたらこんな感じです。`` `` これは写真風のフレーム画像を合わせてますが、切手風のフレームを合わせたのが以下です。`` `` てな感じです。どちらに傾けるかとか(傾けないというのもあります)、写真風か切手風かというフレームの選択は、何れもIMGタグの中でクラス指定をすることで実現します。`` ほかにいくつかデモを並べてみます。`` ` ` `` ` `` ちなみに、IE(インターネットエクスプローラー)はcanvasをサポートしていないので、こちらは[g]VML[/g]を利用して同様の効果を見せるようにしています。こちらで動作が確認できたブラウザは、ウィンドウズではIE7, Firefox2.0でマックではSafariとFirefoxです。OperaやIE6以下は未確認です。`` 一応、このスプリプトは外部読み込み形式で作動するようにしています。ppBlogであれば、各テーマのテンプレートHTMLファイルに、外部スクリプトを呼び込む要領で、``<script type="text/javascript" src="js/photoeffect.js"></script> ``と記述して、あとはlib.js のDOM.onload の最後の行にでも、``if(typeof photoEffect != 'undefined'){` photoEffect.init();`} ``と書いておけば動きます。あ、あと2種類のフレーム用の画像はトップページのImagesディレクトリにアップしておく必要があります。クラス名の指定ですが、IMGタグでのクラス指定で photo-effect が指定されていれば、それを認識して、このスクリプトが発動します。このスクリプトと画像ファイルを添付しておきます。まだ作りたてなので細かいところは見ていませんが興味ある方はどうぞ。```[Update:2007/10/8 17:31:18] ` 傾きの角度は、自由に指定出来るようにしました。クラス名で photo-angle3 や photo-angle-3 みたいに指定します。数字は-360度から360度まで。マイナスの値なら、右肩上がり、正の値なら左肩上がりです。`` あ、ついでにppBlogユーザー向けも。これは、Firefoxに対するマウスオーバーチップ処理を追加しています。``[file:1188848148_photoframes.zip:31.7/]`[file:1188848148_photoeffect.js:4.2/]`[file:1188848148_photoeffect-ppblog.js:5.7/]|martin|1|1|JavaScript||
[80] => 1178378213|開発日誌|アマゾンアソシエイトのテスト|ピアノ・レッスン `` いつのまにか、アマゾンアソシエイト(以下AWS)のプログラムがバージョンアップしてたので(しかも以前とは別物と言って良いほどの変わりよう)、それに合わせてそれ用のPHPスクリプトを書き換え。今回、ほぼスクラッチからamazon_associate.phpを書き上げました。バージョン1.6.2までは、これ以外にもXSL変換用のスクリプトもあったんですが、実は不慣れなXSL言語を使わなくてもPHPだけで、十分実用的なスクリプトが書けることが分ったので、サーバーサイトは(XSLTは使わずに)PHPのみで処理するようにしました。ppBlog上ではこのAWSプログラムは埋め込み型で、記事投稿画面のところで使用しますが、感じをつかんでいただくようにデモを置いてみました。最終的にはppBlog向けのタグが生成されるだけなので、汎用性はありませんが。。 →AWSサンプルスクリプト ``Nespresso エッセンサ ネスプレッソコーヒーメーカー D-90RE `` 技術的なことで言えば、ppBlog上では、記事の中にAWSのタグがあると、動的にアマゾンのサイトから情報を取得してHTMLタグを生成します。これは、表示内容に売上ランキングや動的な価格やアマゾンユーザーの平均評価(星によるrating)を含むためです。こういう内容は、刻一刻と変動するものなので静的なHTMLタグとしてログ化してしまうのは好ましくありません。`` でもここで問題が生じます。最終的なHTMLの生成時間が、アマゾンのサーバーからのレスポンスに左右されてしまうことです。複数のAWSタグがあると、それはレスポンスとして体感できるくらいのタイムラグになります。ppBlogは、軽快さが売りのひとつなのでこういう現象は避けたいです。なので、解決策として、キャッシュファイルを生成するようにしました。具体的には、24時間以内に生成されたAWSのHTMLタグなら、それを表示、もし24時間以上たったキャッシュファイルであれば、削除して新たにアマゾンのサーバーから情報を取得するようにしました。とりあえずは24時間というスパンを取りましたが、これはもっと小さくても良いかもです。`` ちなみに、映画のサントラで好きなものを挙げろと言われれば、間違いなくマイケル・ナイマンの「The Piano」を挙げます。映画の方も好きですが(DVDも所有)、このCDが秀逸過ぎです。彼の作品はほかにも持っていますが、この「[w]ピアノ・レッスン[/w]」でのマイケルは神がかりともいえる旋律を紡ぎ出しています。19曲収録されていますが、個人的には「Big My Secret」「The Scent Of Love」が好き。有名なのは、「The Sacrifice」ですが。@TOWER.JP で各トラックのさびが聴けます(WMA形式)。|martin|1|1|JavaScript||
[81] => 1174904845|開発日誌|現況その2| こんにちは。こちらパリはお昼を回ったところです(昨日からサマータイムで1時間進みました)。渡仏にあたって、いつも使っていたノートPCでは大きすぎるので、新たにノートを購入してそれを使っています。PC移行にあたり、仕事の環境はほぼ移行していたのですが、肝心のppBlog関連の環境移行が中途半端でした。なので、まずはローカル環境へのApache2.2+PHP5のインストールを昨日済ませ、配布中のppBlog1.6.2をダウンロードして、テスト環境が構築できたところです。VistaへのApache+PHPのインストールは、Windows XPのときと勝手が違って、ちょっと苦労しました。`` 4月9日(日本は10日)に帰国しますが、帰国したらすぐに1.6.3 をリリースしようと思っています。現状、ppBlogのデフォルトの文字コードはEUC-JPですが、今、手元のテスト環境ではUTF-8が問題なく動いているので、v1.6.3からは、UTF-8 版も同時配布となります。ほんとは、以前v1.5β版をリリースしたときに、UTF-8移行を考えていたのですが、まだまだEUC-JP全盛で見送っていました。最近はUTF-8がもはや業界標準のようですし、Ajaxを含めたJavaScriptなどはもとよりUTF-8でのやり取りが当たり前ですし、UTF-8を出さない理由がないので出します。現状でさえ、複数の文字コードがあって、それに起因する文字化け問題などがある中、これ以上の新しい文字コード体系なんて不要だろうし、今後はUTF-8に収束していくのかぁ、と思っています。|martin|1|1|JavaScript||
[82] => 1173698841|開発日誌|モブログその2| ``ラボのノートパソコン。SZはサクサクです。メモリ2GBだけど。。``<PCより追記> `` 別の不具合を調べようとしたら、違うバグを見つけた。手動モブログでは、mob.phpにアクセスして認証後に、セッションを開始、モブログメールのチェックをするわけだが、短時間で連続してモブログすると、まだセッションが生きていて、この場合は認証なしにモブログをチェックする。これは良いんだけど、この際に投稿者の名前が設定されないことが分かった。ふぅー[zzz/]|martin|1|1|JavaScript||
[83] => 1173698416|開発日誌|モブログのバグチェックです|ラボのノートパソコン。まSZはサクサクです。メモリ2GBだけど。。``<PCより> ` あ、写真付け忘れた。。|martin|1|1|JavaScript||
[84] => 1171565646|開発日誌|角丸コーナーテスト| リリースに向けて細かいところの調整中。主に管理画面のデザインや操作性になるべく統一性を持たせるように。管理画面でもAjaxを使える所は積極的に使ってます。このおかげで画面遷移なく設定値の書き換えが行われたり、アイテムを削除出来たりと、スムーズな操作性になってます。`` ppBlogでコアなJavaScriptライブラリであるlib.js も色々いじってます。昔のバージョンに付けていたクッキー制御関数を復活させた。手元に以前のソースがなかったので、グーグルのCodeSearch から自分の書いたやつを見つけてきました:> 懐かしい。`` 角丸コーナースクリプトも、まだいじってる途中だけど、、、`` http://p2b.jp/demo/CornerPlay.html`` 週末かなぁ、リリースは。`` 修正すべき点がけっこうあるなぁ。メンテナンスって大変だ。
|martin|1|1|JavaScript||
[85] => 1171206648|開発日誌|アクセス解析ブラッシュアップ| 久しぶりにppBlog標準装備のアクセス解析の手直しをしてみました。中国最大手の検索サイト百度(バイドゥ)が日本語版サービスを開始へ という話は知っていたけれど、そのクローラー来てますねぇ。`` これに合わせ、いくつかのアイコンを作成し、またview.php もこちらで確認できる限りのバグ退治をしました。`` 参考までに、1月末の4日間ほどのOS・プラットフォーム別アクセス解析のショットを挙げておきます。発売されたばかりのWindows Vistaも早速エントリしてました。`` `` あと、新たなアイコン達とview.phpの最新版。view.phpはstatディレクトリにあるやつをそのまま上書き。アイコンはstat/iconディレクトリへ。``[file:1171206648_stat070212.zip:14.8/]|martin|1|1|JavaScript||
[86] => 1171016638|開発日誌|テスト|ハロー。オートポスト。携帯電話から編集です。|martin|1|1|JavaScript||
[87] => 1161791680|開発日誌|YouTubeやグーグルビデオ、Soapboxのための記法|ひとつ前のエントリーで書きましたが、記法は簡単です。次のようになります。``[yt:(ビデオのID):横幅:縦幅] ``YouTubeなら、yt 、Googleビデオならgv 、マイクロソフトsoapboxならsb です。縦と横のサイズ(整数)は省略できるので、簡単にしたいなら、ビデオのIDを記述するだけでOKです。具体例で見ていきましょう。`[yt:hEYHvLnVcnQ::] と記述すると(任天堂ゼルダ曲のピアノ演奏、再生すると音が出ます よ)、`[yt:hEYHvLnVcnQ::]`次は、GoogleVideoの場合。`[gv:-5379890076544103730::] と記述すると(任天堂マリオ曲のピアノ演奏)、`[gv:-5379890076544103730::]`最後に、マイクロソフトのSoapbox。`[sb:022cb97f-95f8-403a-9c1b-5032c70de2e1::] と記述すると(任天堂Wiiのゼルダデモ映像)`[sb:022cb97f-95f8-403a-9c1b-5032c70de2e1::]`` こんな感じです。簡単ですね。この記法のために、スタイルシート用ですが video-link というクラス名を出力するようにしました。このbasicのテーマの場合は、basic.cssにて次のように指定しています。``/*--------------[ 外部動画 ]-------------*/`.video-link {` width: 425px; margin: auto; z-index:1;`} ``` とりあえず、代表的な3つのビデオサイト向け記法を用意しましたが、utils.php のソースを見れば分かるように、今後いくらでも追加できるようにしています。この手のは、たいていFlashを用いていますから。ちなみに、utils.phpの該当部分は以下のようになっています。配列なので、FLASH系なら、いくらでも追加できると思います。`` // 外部動画リンク表示処理 (YouTube, Google Video, SoapBox MSN, and so on...)` if(preg_match_all('{¥[(yt|gv|sb):([0-9a-z¥-]+?):(¥d+?|):(¥d+?|)¥]}i', $com, $movlinks)){` $length = count($movlinks[0]);` $embeds = array( # src, type, others, width/height` 'yt' => array('http://www.youtube.com/v/', 'application/x-shockwave-flash', '', '425,350'),` 'gv' => array('http://video.google.com/googleplayer.swf?docId=', 'application/x-shockwave-flash', 'id="VideoPlayback"', '400,300'),` 'sb' => array('http://images.soapbox.msn.com/flash/soapbox1_1.swf?v=', 'application/x-shockwave-flash', 'wmode="transparent" name="msn_soapbox" flashvars="c=v&v=SB_MOV_ID"', '412,362'), //` );` for($i=0; $i<$length; $i++){` $_mv = NL.'<div class="video-link">'.NL;` $tar = $embeds[$movlinks[1][$i]];` list($def_w, $def_h) = explode(',', $tar[3]);` $w = $movlinks[3][$i]=='' ? $def_w : $movlinks[3][$i];` $h = ($h=$movlinks[4][$i])=='' ? ($movlinks[3][$i]=='' ? $def_h : ceil($w * .75)) : $h;` $_mv .= ' <object style="width:'.$w.'px; height:'.$h.'px;">` <param name="movie" value="'.$tar[0].$movlinks[2][$i].'"></param>` <embed src="'.$tar[0].$movlinks[2][$i].'" type="'.$tar[1].'" '.str_replace('SB_MOV_ID', $movlinks[2][$i], $tar[2]).' width="'.$w.'" height="'.$h.'"></embed>` </object>';` $_mv .= NL.'</div>'.NL;` $com = str_replace($movlinks[0][$i], $_mv, $com);` }` } |martin|1|1|JavaScript||
[88] => 1158056947|開発日誌|3ペインの新しいテーマ| こんばんは。ケータイの着信音をジャックバウアーの「[g]24[/g]」(ピッ、ピッ、ピッってなるやつ)にしているのですが、仮眠中に鳴った着信音に起きるどころか、何故か、ジャックと一緒に、日本の某所で潜入捜査をしていて「日本だけに、銃が使えないよね」 と匍匐(ほふく)前進しつつ、ジャックに夢の中で話しかけていたmartinです。`` さて、ppBlog1.5版では、デフォルトでついているテーマは、2ペイン(サイドバーとメインコンテンツの2カラム)のベーシックなやつですが、それ以前のバージョンには3ペインのテーマも付けていました。で、1.5系に対応する手間だとか、配布ファイルサイズが大きくなるからなどの理由で、1.5系からは付けていなかったのですが、3ペインの要望もあり、とりあえず1.5系に対応させてみました。自分の3ペインには、「こだわり」があって、クリックで2ペインと3ペインの切り替えが出来たり、ソースを見ると、メインコンテンツがサイドバーの内容より先に表示されるとかです。`` まだ、細かい詰めはこれからなのですが、まぁまぁの出来かなと思っています。記事日付の表示に少し凝ってみました。これは、1.5β版で作成していたテーマ「le chic」などでも似たようなことはやっていたんですが、「日めくりカレンダー」のような雰囲気です。ちなみに、「りえっぺさん のと似てない?」という突っ込みはなしで。。`` 日付周りは、テーマディレクトリにあるtemplate.phpの記事ボックススタイルで指定するわけですが、実は、それなりに多彩な表現が可能です。このカレンダーっぽい日付の部分は以下のように指定しています。``<p class="article-date" title="%_ARTCL_DATE_FORMAT[g:iA]_%">` %_ARTCL_DATE_FORMAT[D]_%` <em>%_ARTCL_DATE_FORMAT[d]_%</em>` %_ARTCL_DATE_FORMAT[M]_%` ’%_ARTCL_DATE_FORMAT[y]_%`</p> ``これに対応するスタイルシートの指定は、article-date というクラス名に対して、``.article-date {` width: 48px; height: 48px;` color: #585d86;` float: left; /* この指定がポイント */` text-align: center;` font: 500 11px Arial, sans-serif;` margin-right: 10px;` background: url(Images/date.png) no-repeat;`}`.article-date em { /* 日付の太文字数字に対応 */` font: 800 23px Georgia, serif;` text-decoration: none;` display: block;` margin: -6px 0 -3px 0;`} ``という指定をしています。template.phpでのポイントは、%_ARTCL_DATE_FORMAT[*]_% という日付に関する変数を複数回 用いていることです。これの(*)の部分にはPHPのマニュアルにある日付に関する様々なフォーマット文字を入れることが出来ます。詳しくは、マニュアルの該当箇所 をどうぞ。`` ちなみに、このテーマは、途中なので、まだテーマのプルダウンメニューに入れていませんが、http://p2b.jp/index.php?theme=theme/3pane2/3pane.css で見ることが出来ます。|martin|1|1|JavaScript||
[89] => 1153728573|開発日誌,JavaScript|document.write()の実行タイミングをずらす方法|`` このサイトのppBlog's webRingのリストは、BlogPeople からdocument.write で書き出しています。というかBlogPeopleのスクリプトがそうなっているのですが。で、document.writeが、HTMLソースの最初の方にあると、document.writeによる書き出しが終わるまで、それ以降のページのレンダリング(HTMLの書き出し)はストップした状態となります。document.writeによって呼び出している外部サーバー(ここではBlogPeople)のレスポンスが速ければ、ページ描画で待たされることはありませんが、たまにはレスポンスが遅くて、ページの残りがなかなか表示されないという事態は起こりえます。このdocument.writeは、広告バナーなどでも当たり前のように使われていて、メインコンテンツの内容が知りたいのに、バナー広告がなかなか表示されず、イライラしたという経験もあるかと思います。確か、GoogleのADWordsなどでも使われているのではないでしょうか。`` こういう事態を避けるには、HTMLソースの最後の方で document.write を呼び出すというのがあり、これはこれで有効ですが、そう汎用性のあるやり方ではなく、また、スクリプト(JavaScript)がHTMLの中で、あちこちに散らばるのは美しくないです。`` ここでは、document.writeの内容をとりあえず配列などに一時的に退避させといて(この間にHTMLソースの描画は進んでいきます )、ページ読み込み完了と同時に、そのストックしておいたdocument.write内容を吐き出すという方法について書いておきます。`` まず、普通にdocument.writeを含んだ外部スクリプトを呼び出すやり方。これは、BlogPeopleがこうしましょう、と述べているものです。``<script type="text/javascript"` src="http://www.blogpeople.net/display/usr/0f0d40535b5b4103.js"` charset="euc-jp"></script> ``これの実際の中身は、次のようになっています。``document.write('<div class=¥'blogpeople-main¥'>');`document.write('登録されたサイト')` :` :`document.write('</div>');`document.write('<div class=¥'blogpeople-powered-by¥'>');`document.write('<br /><a href=¥'・・・¥' target=¥'_blank¥'><img src=¥'・・・¥' border=¥'0¥' alt=¥'Powered By BlogPeople¥' /></a>');`document.write('</div>'); ``ここに使われているdocument.write内容をとりあえず配列に入れておけば良いのですが、それには次のようにします。```(function(){` var alts = []; // document.writeの内容を入れておく配列を準備 ` d._write = d.write; // オリジナルはコピーしておく ` d.write = function(s){ alts.push(s);} // d.writeを新たに定義 ` var src = "http://www.blogpeople.net/display/usr/0f0d40535b5b4103.js";` var script = d.createElement('script');` script.setAttribute('type', 'text/javascript');` script.setAttribute('charset', 'euc-jp');` script.setAttribute('src', src);` d.getElementsByTagName('head')[0].appendChild(script);` addEvent(window, "load", function(){` o("_webRing").innerHTML = alts.join(""); // 指定した場所に流し込む ` d.write = d._write; // d.writeを元の定義に戻しておく ` });` }()); `` ポイントは、既存のdocument.writeを新たに、``document.write = function(s){ alts.push(s); } ``と再定義している点です。ここではalts という配列に退避させています。こうすることで、document.writeによる書き出しを待つことなく、残りのページレンダリングを進めていくことが出来ます。このスクリプトで、SafariでもIE6でもFirefoxでもきちんと動くことを確認しています。`` 小生のブログであるmartin.p2b.jpのwebRing と、このサイトにあるwebRing とは同じ外部スクリプトを呼び出しているのですが、比較のために、このサイトのwebRingは上記の手法で、martin'sの方は従来の方法で呼び出しています。BlogPeopleのサーバーレスポンスは素早いので、なかなか差が実感できにくいかと思いますが、このサイトのやつは、(サイドバーのHTMLソースはdocument.writeよりも後にもかかわらず)サイドバーが先に表示されて、最後にwebRingのリストが表示されるのに対して、martin'sの方は、HTMLソースの順序通り、webRingリスト→サイドバーという順序で表示されています。`` ちなみに、このサイトのwebRingは、ppBlogの「ページ作成機能」を使って作成しているのですが、具体的に、どのような内容になっているのか、理解の一助のために添付しておきますね。`` まぁ、こんなアプローチもありますよということで [署名/]``[file:1153728573_webRing.txt:0.9/]|martin|1|1|||
[90] => 1153063960|開発日誌|現時点でのlib.jsほか動画ファイル関連| Opera9でのAjax関連のスクリプト動作がちょいと怪しいので、一応Opera9でも何とか動くようにlib.js を修正してみました。以前から、OperaのinnerHTMLの挙動は不審な点があるんですよね。バージョン9になっても、それほど改善はされていないのかなぁ。自分のところにくるOpera使いは3パーセント台で決して多くはないのですが、モダンなブラウザであることに変わりはなく無視するわけにもいきませんので。`` あと、バージョンアップに際して、動画ファイルの扱い を見落としていました。バージョン1.5からは、今後のポッドキャストや音楽ファイルの配布なんかを見据えて、これまでの動画ファイルは画像ファイルと切り離して、画像ファイル と、その他のメディアファイル という扱いにしています。それに伴い動画ファイルのログ形式もちょっと変えたのでした。これは、スクリプトの方で、1.4系もカバーするようにします。ついでといっては何ですが、メディア関連の画像が抜けていたり、ほかに、メディア関連の出力タグに、これまでスタイルシートのクラス名を指定していなかったので、これもクラス名を設けました(class="media-part" )ので、添付しておきますね。`` 現状では、画像データベースは備えていますが、メディアデータベースはまだです。まぁ、これは画像データベースの流用で、ある程度簡単に実装できると思いますが、動画・音声系は、もうちょっと機が熟してからでよいかなと思っています。バージョン1.5.5ぐらいで? 個人的には、ポッドキャストを勉強して、それをある程度扱えるようになったらと思っています。外枠を捉えるのはそう難しいものではないでしょう。実際のコンテンツ作成は別として。`` というわけで、1.4系の動画ファイルを考慮した、そして、今後のメディア関連の扱いもある程度意識したutils.phpとutils_admin.phpを添付しておきます。その他、メディアアイコンと最新版のlib.jsを添付しておきます。`[file:1153060946_DIFF060717.zip:48/]|martin|1|1|JavaScript||
[91] => 1152813732|開発日誌|今日あたり・・・| こんばんは。プレッシャーもあって、ひっそりとppBlog1.5.0正式版をアップしていたんですが、いくつか修正点があって、それらのフィックスを合間合間にやってましたが、大体片が付いたので、今日あたりに1.5.1 として、正式版をきちんとしたアナウンスのもとにリリースしようと思います。何だか読みにくい日本語になってしま(略)。`` これまで、記事作成画面では、「ワープロモード」と「ローカルプレビュー」が付いていたんですが、ワープロモードはAjaxを利用した「自動ポスト機能」にとって替わりまして、また「ローカルプレビュー」は、従来のものは、ほんとおまけ程度の貧弱なものだったんですが、今回のバージョンからは、デフォルトのテーマをほぼ忠実に再現します。まだ、完璧に再現する訳ではないのですが、ウェブ上での見た目と殆ど変わらないレベルだと思うので、皆さん、活用されて下さい。`` 余談ですが、IE に関して、自分はIE7b3を試用中でして、IE6の数あるスタイルシート(CSS)関連のバグはほとんど修正されています。で、IEの動作確認は、ついついこのIE7で済ませてて、まぁOKかなって思っていたら、ご指摘があって、Ajax関連の新しいギミックが、CSSと相まって、IE6ではありえない動作をしたりするんですよね。何じゃ、このIEイィィィィィィ、と思わずDIO になりそうなのをこらえて、何とかIE6にも対応させました。それにしてもIE6のシェアって、このブログの来訪者で見ても6割超なんですよね。。無視できません[zzz/]` ` |martin|1|1|JavaScript||
[92] => 1152214827|開発日誌,JavaScript|window.onloadの代替スクリプト|Updated Entry : http://p2b.jp/200805-events-order ``` 今日は[w]七夕[/w]ですね。小学生の頃は、学校総出で「♪笹の葉さーらさら〜」ってやって、七夕伝説に思いを馳せたものですが。いつになってもガキの頃の心を忘れない大人でいたいものです。`` さて、Ajax の隆盛によって、その根幹であるJavaScript はブログに欠かせないものとなっています。ppBlogも例外ではなく、至るところで活躍してます。一般にブログの(トップ)ページは、色々な情報を詰め込んでいるために、ファイルサイズは大きくなる傾向にあり、また、画像も至るところで使われるために、読み込むべきコンテンツサイズは更に大きくなります。ブロードバンドが当たり前の今日でもページの表示にちょっと待たされるのは珍しいことではありません。で、JavaScriptは(画像も含めた)ページの内容物が全部読み込まれた後に作動させるのが一般的です。なので、もし、画像の読み込みに時間がかかったりすると、JavaScriptがうまく動かずに、狙い通りの効果が得られなかったり、スクリプトエラーが出たりします。こういうのはたいてい、window.onloadやBODYタグでのonloadイベントで制御しているんですが、JavaScript使いなら、画像の読み込みを待たずに、ページの構成要素(DOMエレメント)がパース(読み込まれて解釈)された時点でプログラムを走らせたいと思うものです。`` その解決法として、JavaScriptマスターのDean Edwards 氏が、window.onload問題を解決した! と言ったのが昨年の9月頃で、このブログでも言及した ことがあります。彼のやり方は、Mozilla系ブラウザの隠し要素DOMContentLoaded を利用したもので、IEはこれに対応していないので、IEだけは、外部jsスクリプトを用意しないといけませんでした。その不完全さが好きになれなかったので、ppBlogではこれとは違うアプローチ(setTimeoutを利用するやり方)を取ってたんですが、このsetTimeoutがらみの手法は、PCの性能などにも大きく左右されるし、どうも不安定さがあるんですよね。角丸コーナースクリプトが上手く作動しなかったり。`` そんな折、先月にこれでほぼ100%解決と思われるやり方がEdwardsを含めたJavaScriptマスターたちによって「発見」されました。→http://dean.edwards.name/weblog/2006/06/again/`` この新しい方法では、IEでも外部スクリプトを別に用意する必要がなく、またSafariなどでも問題なく動くものです。いやぁ、みんな頭良いよなぁ。自分でも個人的に、IE向けにはdocument.readyState を利用した方法を試したりしたんですが、IEの返すdocument.readyStateが、またいい加減なシロモノでしてあえなく挫折。しかも、DOMContentLoaded に関しては、Operaの最新バージョンであるOpera9でサポートされたりしたんで、自分もこの潮流に乗っかることにしました。そのうちSafariでもDOMContentLoadedはサポートされそうな予感。そういえば、Opera9では、とうとうdocument.designModeがサポート されましたね。以前、[g]document.designMode[/g]を利用して、ppBlog組み込みの本格的なエディターを作ろうとしたことがあったのですが、IEの吐き出すHTMLソースがあまりに後進的だったので放置したままになっていますねぇ。IE7βでどうかはまだ試していないです(期待してないけど)。`` 少し逸れましたが、とにかくppBlogでもwindow.onloadに替わる新しいやり方を実装してみました。詳しい話はエドワーズのブロッグを読んでいただくとして、ppBlogでは現時点で、次のような感じにまとめています。``DOM = { /* window.onload alternative */` complete : function(){` if(arguments.callee.done) return;` arguments.callee.done = true;` if(typeof _timer != 'undefined'){` clearInterval(_timer);` _timer = null;` }` DOM.onload();` },` check : function(){` if(d.addEventListener){ // Mozilla/Opera9向け` d.addEventListener("DOMContentLoaded", DOM.complete, false);` }` if(navigator.userAgent.match(/webkit|safari|khtml/i)){// Safari向け` var _timer = setInterval(function(){` if(d.readyState.match(/loaded|complete/)){` DOM.complete();` }` }, 50);` }` /*@cc_on @*/` /*@if (@_win32)// IE向け` d.write('<script id="_decoy_" defer src="javascript:void 0"><¥/script>');` d.getElementById("_decoy_").onreadystatechange = function(){` if(this.readyState=='complete'){` DOM.complete();` }` };` /*@end @*/` addEvent(window, "load", DOM.complete);//その他` },` onload : function(){}`} `` ポイントは、DOMContentLoadedをサポートしているならそれを使い、Safari系ではdocument.readyStateを利用し(IEと違って信用できる値を返すようである)、IEではスクリプト属性のdefer を利用することです。このdeferは文字通り、(外部読み込み)スクリプトの実行を遅延させる属性でIEのみがサポートしています。このdeferは、document.readyStateよりずっと堅実です。ついでに言うと、ここで使われているdefer指定の外部スクリプト指定は、もはや単なる「飾り」になっています(それがIE7正式版でどういう扱いになるか一抹の不安が残りますが)。詳しくは、このトリッキーな手法を発見したMatthias Miller 氏のブログ(エントリー )をどうぞ。`` ちょっと話題がずれますが、IE7βは先日ベータの最新版かつベータ最終版が出ましたね。それに少し関連したErik氏の面白いエントリーがあったので紹介しておきます(まぁ、期待外れ感が漂う、ちょっとしたジョークなんでしょう)。`` →IE 7 DOM and JS Changelog `` Erik氏は、昨日のエントリーにも出てきたWebFXの主宰者の一人で、彼もまたJavaScriptマスターです。このエントリーは時期的にIE7ベータ1-2についてのものかな。思わず笑ってしまいました [署名/]|martin|1|1|||
[93] => 1152131691|開発日誌,JavaScript|Firefoxでのwindow.event| ワールドカップの準決勝ポルトガル-フランスのせいで寝むれないmartinです。``以前のエントリで「Firefoxでの擬似window.event 」として、``function windowEvent(){` if(window.event) return window.event;` var caller = arguments.callee.caller;` while(caller){` var ob = caller.arguments[0];` if(ob && ob.constructor == MouseEvent) return ob;` caller = caller.caller;` }` return null;`} ``というのを載せていましたが、どうせなら、Firefox(および、その他のモダンなブラウザ)にも、window.event を認識させたいです。window.eventは使い勝手が良いので。で、このwindow.eventを簡単に認識させる方法があったので、今はこれを使っています。もともとのソースは、JavaScript使いなら誰でも知っている、昔からの有名サイトWebFX 内にある「Classic Event Handlers - IE Emu 」で紹介してあった方法です。リンク先を見れば分かりますが、これ以上ないくらいシンプルでスマートなやり方ですねぇ。最初は、__defineGetter__ あたりを使ってエミュレートしようとしていたのですが。いやはや。`` js/lib.js では、次のようにしています。``if(w3c){ // IE以外のモダンなブラウザなら.` (function(){` for (var property in Event.prototype){` if(property.match(/MOUSE|CLICK/)){` window.addEventListener(property.toLowerCase(), function(e){` window.event = e;` }, true);` }` }` }());`}; `` イベントリスナーに逐一マウスイベントを列挙して登録しても良いのですが、Eventオブジェクトにある組み込み定数を利用してみました。マウスイベントを列挙するなら、次のような感じになると思います。``if(w3c){ // IE以外のモダンなブラウザなら.` (function(){` var events = ["mousedown", "mouseover", "mouseout", "mousemove",` "mousedrag", "click", "dblclick"]; ` for (var i = 0; i < events.length; i++){` window.addEventListener(events[i], function(e){` window.event = e;` }, true);` }` }());`}; `` まぁ、こちらの方が記述も短めでオーソドックスなやり方ですが、イベントを列挙するのがメンドかったので、別のアプローチを取ってみました。お好きな方でよいと思います。`` こうすると何が嬉しいかって、例えば、次のようなスクリプトにおいて、``document.onclick = function(e){` alert("Event X:"+e.clientX + ", Event Y:"+e.clientY);`} ``この引数のe は、Mozilla系のブラウザでは必須のもので省略は出来ません。こういうシンプルな例ならいいのですが、引数がいくつかあるような関数で、いちいちこのe を付けて回るのはメンドいものです。こういうときに、上記のエミュレーションを用いれば、``document.onclick = function(){ //e が不要` alert("Event X:"+event.clientX+", Event Y:"+event.clientY);`} ``みたいに書けるわけです [署名/]|martin|1|1|||
[94] => 1152120960|開発日誌|リスト表示ならAjaxで読み込み| リスト表示のときは、Ajax経由で記事を読み込んで表示させるという感じにしてみました。細かいところの詰めなどあると思いますが、雰囲気は味わえると思います。やっぱり、Ajaxを使うと記事のデータだけをダウンロードするので、ページ全体を読み込むのに比べて表示が速いですね。`` このギミックについて何かアイデアなり、希望などがあればコメントお願いします。|martin|1|1|JavaScript||
[95] => 1151498116|開発日誌|Ajaxによる自動投稿スクリプト| フォーラムで,一旦投稿した後に,引き続き編集作業を継続できないかという問い合わせがありました。ppBlogでは,公開される通常の投稿であれ非公開のドラフト投稿であれ,ポストした後は一旦トップページを表示するような流れになっている訳ですが,確かに,そんなのもありだなぁと思った次第。編集画面から投稿後のトップページへの切り替えはJavaScriptを使っていて,とりあえずは,この行き先を変更すれば,投稿後に編集画面に戻ることが出来ます。これはnaoKさん が解決法をフォーラムの方に書いてくれてます。` →http://forum.p2b.jp/index.php?mode=box&UID=2870&display=all`` で,ppBlogは[w]AJAX[/w]の技術をコメント表示などに用いており,またログイン認証ではAJAXでポストということもしています。なので,記事の投稿もAJAX経由でいけば,編集画面から離れることなく,バックグラウンドでのドラフト投稿が出来そうだと思い,スクリプトを書いてみました。`` まずは,AJAX経由でポストするので,そのための準備をします。POST送信で送るパラメータは Array.push() メソッドを用いて,どんどん追加していって,最後に Array.join('&') で連結すればOKです。これをppBlogに組み込まれているAjax.post() メソッドを使ってPOST送信すれば良いです。これは以下のような感じになります(細かな条件振りなどは省略して書いています)。```function AjaxAutoPost(){` var posts = [];`` posts.push('mode=update');` posts.push('UID='+o('UID').value);` posts.push('draft=1');` posts.push('type=autopost');` posts.push('category='+o('category').value);` posts.push('title='+encodeURIComponent(o('_title').value));` posts.push('author='+encodeURIComponent(o('author').value));` posts.push('com='+encodeURIComponent(o('Page1').value));` ` posts = posts.join('&'); // posts配列を&で連結`` Ajax.post("admin.php", posts, function(data){ // AJAXでPOST送信` [data processing] ` });`} `` これをバックグラウンドで,自動的に一定時間ごとに行いたいので,setTimeout を用いて,この関数を繰り返し呼び出せばOKです。`` 次にサーバーサイドですが,こちらはPHPでの処理となります。日本語をJavaScriptでエンコードすると,もとの文字コードが何であれ,必ずUTF-8化して送出してくれます。なので,ppBlogで扱う文字コードがUTF-8以外の場合は(例えばデフォルトでのEUC-JP),その文字コードに変換してからログに記録するようにします。`` ` ` ` ` このオートポスト機能を追加したppBlogでの記事作成画面のスクリーンショットを載せておきます。図にあるように,自動ポスト開始ボタンがあって,それをクリックすることによって,一定時間毎でのオートポストが開始されます。始動中は,ボタンが「一時停止」のボタンに変化していて,もう一度ボタンを押すと,オートポストを中断します。ボタンの隣のテキストボックスには,最後に自動ポストした時刻が表示されます。ボタンで自動投稿オンオフの切り替えが可能です。`` この機能を取り入れることの利点は,バックアップも兼ねる点でしょうか。記事をシコシコ書いて,いざ送信!って送信するとサーバーのレスポンスが悪かったりして,折角したためた記事がパーになってしまった経験が,自分は少なくとも3回あります。この自動ポストを使って,初めのうちからドラフト投稿しておけば,こういう痛い状況は極力減ると思います。`` 当初は,記事をブラウザのクッキーに保存するオートセーブ機能みたいなやつも念頭にあったんですが,クッキーにはせいぜい4キロバイトぐらいが限度で(参照:クッキーの最大サイズ制限について ),この容量ではとても長文には耐えられませんし,そもそもクッキーの用途とはずれている気もしますし,ここはppBlogで比較的簡単に実装できるAjaxを使うアプローチを取ってみました。`` まだ細かいところまでチェックしたわけではないんですが,試しに使ってみたいという方はどうぞ。`簡単な説明文も一緒にZIPしておきます。ちなみに,editor.js のお尻の方に今回のスクリプトを追記していますが,そこにでてくる60000 という数字が,自動投稿の間隔を表しています。この場合は,60000ミリ秒すなはち1分おきにオートポストするということです。ここの数字を変えることでお好きな間隔に設定できます [署名/]|martin|1|1|JavaScript||
[96] => 1149856040|開発日誌|タグ機能を使ったテクノラティへの検索リンク| ppBlogの最新版には、タグ機能が付いています。「タグ」と「カテゴリー」は使い方が同じように感じるかもしれませんが、やっぱり違いますね。タグは「キーワード」とほぼ同等と個人的には思っています。ある記事があって、その内容と繋がりを持ったキーワードというものがある。そして、そのキーワードは記事を分類するカテゴリーとは別の要素です。だぶっても良いと思いますが。`` てなわけで、ppBlogにシンプルなタグ機能を付けてみました。このタグ機能は、ppBlogの中で完結するものですが、折角なので、Technorati JAPAN にリンクするタグも出力できるようにしてます。テクノラティジャパンのタグ検索機能は、2005年12月29日にベータ版のサービスが提供されていて、未だにベータ版ですが、まぁこれはグーグルのGmail がそうであるようにずっとβ版ということかもしれません。ちょっとサイトが重いんじゃないかと感じますが、これからの改善に期待してます。`` テクノラティでは、記事の更新PINGも受け付けており、ppBlogの管理画面で、テクノラティの更新PINGを登録すれば、より効果的にタグを活用できるのではないでしょうか。`` ppBlog自体のタグ機能について、簡単に述べておくと、タグは、記事の新規作成時や編集時に自由に追加や削除が可能になっています。そして、大体、どのブログでもそうであるように、エントリー数の多いタグほど文字サイズが大きいです。カテゴリー毎のソートが出来るように、タグによるソートも可能です。`` とりあえず、これぐらいの機能でよいかなぁと。|martin|1|1|JavaScript||
[97] => 1149573397|開発日誌|モブログのテスト|[PCから追記@2006/6/6 23:5:33] `` なんとか自動モブログ・複数ファイル添付もOKのようで。ちなみに、ケータイの機種は[g]SO902i[/g] 。ネット情報では写真の質はお世辞にも良いとは言えない感じであったが、これぐらいの大きさであればまずまずではなかろうか。日曜の朝、チェックアウトを済ませてテニスに向かう前に、記念に一枚。大谷山荘は、すごく山奥にあるという感じの、非常に奇麗な巨大ホテルでした。山荘っていうから何となく浅間山荘みたいなイメージがあったのだけれど、全然違った。「山荘」というネーミングはどうなのかなぁ。(666って[g]獣の数字[/g]じゃないか、くわばらくわばら)` 大谷山荘とケータイに始めからあるアニメーション添付(自動エントリー)|martin|1|1|JavaScript||
[98] => 1149276075|開発日誌,JavaScript|Firefoxでテキストエリア内のマウスカーソルが最初に戻ってしまう件| こんばんは。何だか、[g]地球特捜隊ダイバスター[/g]みたいなタイトルになってしまいました。近頃は、もっぱらFirefoxで記事を書いていますが、この際に、ひとつ「何じゃ」と思っていたことがあります。記事作成画面で記事をしこしこ書いていて、時々、文字を強調したり文の整形のために、ppBlogツールバーから選んでタグを反映させますが、その際にFirefoxだと、テキストエリアにフォーカスを合わせると、マウスカーソルがテキストエリアの先頭に移動しちゃうんですよね。なので、その都度、また修正を加えた場所までスクロールさせないといけません。文章が長くなってくると、スクロール量も増えて大変。で、ブロッグは書いてなんぼ、こういう所でストレスを感じさせるようではイケナイ。というわけで、webを検索したらちゃんと便利な属性がありました。ちなみにIE エンジンならマウスカーソルは、修正を加えた箇所にとどまってくれるので問題ないです。`` テキストエリア内で垂直方向にスクロールした距離は、次のプロパティーで読み書き 可能です。``object.scrollTop ``なので、予め、この値を取得しておき、内容に修正を加えた後で、再度この値に設定すれば良いです。具体的には、ppBlogのlib.jsで言えば、``var s = ed.selectionStart;`var scrollTop = ed.scrollTop; `ed.value = ed.value.slice(0,s)+ed.value.slice(s).replace(caretSelection, string);`ed.setSelectionRange(eval(s+string.length), eval(s+string.length));`ed.scrollTop = scrollTop; `ed.focus(); ``とすれば良い。ホットピンクの部分が変更した箇所です。これで、Firefox でもストレスなく記事が書けます。``` 余談ですが、Firefoxの最新版は、1.5.0.4 で6月2日にバージョンアップしています。最近のFirefoxは、アップデートもほぼ全自動ですし、良い感じですね。最近、見つけたTipsは、「スムーズスクロールを使用する 」です。自分がIEエンジンから、なかなかFirefoxに乗り換えることが出来なかった最大要因が、何か皮を一枚被ったような「もっさり」感でした。どことなくスムーズでない。で、よくよく注意してみると、どうもスクロール時のぎこちなさが原因じゃないかと思いました。そういえば、設定項目にスクロールの項目があったような、と、「ツール」→「オプション」→「詳細」→「一般」の「ブラウズ」という項目にありました。デフォルトではオフになってるんですね(自分が以前に弄ったのかも知れないけど)。で、これをオンにすると、マウスホイールでのスクローリングのスムーズなこと!おぉー、これこれ、って感じでした[にこっ/] 皆さんも一度、試されては■|martin|1|1|JavaScript||
[99] => 1149066600|開発日誌,JavaScript|Firefoxでの擬似window.event|`
Follow-Up 2006-7-6
` Firefoxでもwindow.eventを有効にするやり方のエントリーは
こちら `
`` Gecko系のブラウザでは、これはNetscape4.x時代からずっとそうなんだけど、イベントは、イベントハンドラーにargument として渡されるので、この手の記述には必ず引数(ひきすう)を書く必要がある。一方、IEでは(Operaもか?)、イベントモデルには、最後に生じたイベントをキャプチャーするwindow.event という属性があり、これはどこからでも自由にアクセスすることが出来る。以上のことをまとめると、イベントに関してクロスブラウザーな記述をしようと思えば、例えば以下のような感じになる。``function getEventType(e){` var e = e || window.event;` alert("Event Type is:" + e.type);`} `` で、ここで引数に使用している"e " であるが、これはGecko系のためだけに必須である。window.event であれば、この引数は不要だ。で、自分は常々、この"e "を追放できないかなと思っていた。何しろ、イベントを絡ませるような関数に必ずついて回るからだ。スクリプトの記述はシンプルなのが良いのに、この"e " のために余計に引数が増えてしまう。`` ppBlogでは数箇所に、この"e " が出てくるので、こいつを追放してやろうと決心した。そして色々弄った結果、これならOKかなというのを見つけたのでメモしておく。もちろん、ppBlogにも反映される。`` まず、最初にやったことは、ppBlogのjs/lib.jsに記述してある、ページ内でのマウスイベントX座標をゲットする以下の関数において、Firefoxでイベントがどんな風に呼び出されるのかだ。```function getEventPageX(e){` var e = e ||window.event;` if(e.pageX){` return e.pageX;` } else if(e.clientX){` if(d.documentElement && typeof d.documentElement.scrollLeft != "undefined"){` return d.documentElement.scrollLeft + e.clientX;` } else if(d.body && typeof d.body.scrollLeft != "undefined"){` return d.body.scrollLeft + e.clientX;` }` }` return 0;`} `` 実行している関数自身は、arguments.callee で参照出来る。そして、この関数が何によって呼び出されているかは、caller プロパティーを参照すればいい。これらを使って、上の関数に、`` alert(arguments.callee.caller); ``を付け足してみると、Firefoxでは、```function onclick(event){` getEventPageX(event);`} ```というのが返ってくる。→デモ1。 ほほう。ちなみにIEでは```function anonymous()`{` getEventPageX(event);`} ``という匿名関数が返ってくる。Firefoxでは、引数のevent がonclick 関数によってキャプチャーされていることが分かる。じゃ、このonclick関数のevent って何だろう。これは次のようにして調べることが出来る。`` alert(arguments.callee.caller.arguments[0]); ``すると次の答えが返ってくる。→デモ2 ``[object MouseEvent] ``ほうほう。イベントは、マウスイベントオブジェクトとしてonclick関数に組み込まれているらしい。ならば、これを呼び出して、"e " に渡してやれば、"e " の束縛から逃れられるのではと推察する。なので次のようにして、"e " なしのやつを走らせてみる。→デモ3 ``function getEventPageX(){` var e = arguments.callee.caller.arguments[0] || window.event;` if(e.pageX){` return e.pageX;` } else if(e.clientX){` if(d.documentElement && typeof d.documentElement.scrollLeft != "undefined"){` return d.documentElement.scrollLeft + e.clientX;` } else if(d.body && typeof d.body.scrollLeft != "undefined"){` return d.body.scrollLeft + e.clientX;` }` }` return 0;`} `` おおぉー、上手く行った[にこっ/] 3つ目のデモでは、もはや引数のe は必要なく、getEventPageX()`だけで座標を取得していることに着目。`` こりゃいいやと、js/lib.js やjs/editor.js に出てくる引数"e "をとりあえず、全部なしにしてブロッグを見てみると、意図したように動かない。何でかなと、デバッグダイアログを見てみると、これまでのデモでは、マウスクリックによって直接getEventPageX()を呼び出していたのに対して、実際のスクリプトでは、getEventPageX()などは、別の関数の中で呼び出されている。なので、``arguments.callee.caller.arguments[0] ``だと、getEventPageX()を含んだ関数の第一引数を返してしまうのである。初歩的ミス。。それならば、``arguments.callee.caller ``を次々に呼び出していけば、そのうち、マウスイベントオブジェクトに到達するはずである。イメージ的には、sourceに向かって遡っていくイベントバブリングですね。これは次のような記述でいい。``var caller = arguments.callee.caller;`while(caller){` var ob = caller.arguments[0];` if(ob == '[object MouseEvent]') return ob;` caller = caller.caller; // 次の呼び出し元にセット`} ``ただ、ob == "[object MouseEvent]" というのは何となく「カッコ悪い」。この部分はコンストラクタを用いて次のようにも書ける。``ob.constructor == MouseEvent `` 以上をまとめて、IEでも使えるようなクロスな記述にすると以下のような感じ。``function windowEvent(){` if(window.event) return window.event;` var caller = arguments.callee.caller;` while(caller){` var ob = caller.arguments[0];` if(ob && ob.constructor == MouseEvent) return ob;` caller = caller.caller;` }` return null;`} `` windowEvent()がそのままIEのwindow.eventに相当する。これを用いればイベント関連の記述に必須であったe からめでたく解放される訳である。最初に出てきたgetEventPageX()関数は、最終的には次のように記述できる。```function getEventPageX(){` var e = windowEvent();` if(e.pageX){` return e.pageX;` } else if(e.clientX){` if(d.documentElement && typeof d.documentElement.scrollLeft != "undefined"){` return d.documentElement.scrollLeft + e.clientX;` } else if(d.body && typeof d.body.scrollLeft != "undefined"){` return d.body.scrollLeft + e.clientX;` }` }` return 0;`} `` もはやイベントのキャプチャーのためだけに引数は必要ない。最終的なデモをあげておきます。` →http://p2b.jp/demos/windowEvent.html` なお、イベント座標取得関数とは別に、イベントが起こった要素の座標を返す、getElementPosition()という関数も新たに定義しています。これは、JavaScriptマスターであるppk氏 のサイトにある"Find Position " という記事に紹介されている関数をmodifyしたやつです。こんなやつ。```function getElementPosition(){` var _x = _y = 0;` var ob = windowEvent().target || windowEvent().srcElement;` if(ob.offsetParent){` while (ob.offsetParent){` _x += ob.offsetLeft; _y += ob.offsetTop;` ob = ob.offsetParent;` }` }` return [_x, _y];`} `` とりあえず [署名/]|martin|1|1|||
[100] => 1148493255|開発日誌|HSVマップ組み込みと角丸コーナースクリプト| 次のリリースに盛り込む予定のもの。`` 記事作成画面では、216色のカラーチャートから文字やマーカー色を選べますが、個人的には216色じゃ足りなくて不満。なので、フルカラー?にしてみました。スクリプト的にも、216個のセルにイベントを設定していた前作に比べ、こちらは画像1枚なのでベターかなと。[w]HSV[/w]は色々勉強になった。`` あと、ボックスの4隅が丸い、いわゆる角丸コーナーですが、それを実現するためのテクニックは、web上にゴマンとあります。ppBlogのjs/script.jsにもそれっぽいやつがありますが、これは画像を使用するし、またその画像に色を揃えるためボックスの背景色も決め打ちになってしまいます。これは宜しくないので、Liquid round corners を読みつつ、じゃ、これをJavaScriptで書いたらどうなるかなと思ってとりあえず書いてみました。画像は使用していません 。また、アンチエイリアスを少しだけ意識してみました。ボックスの背景色に合ったボーダーの色とアンチエイリアスを自動的に算出してくれるし、指定することも可能。とりあえず書いただけなのでソースは非常に汚い。一応デモページをあげておきます。`` →http://p2b.jp/demo/HSVmap_Rounded_Corner.html`` |martin|1|1|JavaScript||
[101] => 1147275586|開発日誌|画像ポップアップスクリプトをLightboxみたく| ppBlogでは、もとより記事に貼り付けられた画像を元の大きさで表示する画像ポップアップというのを備えてましたが、近頃では、Web2.0 に触発されてか、ThickBox だの、Lightbox だの、GreyBox といった、画像表示に際して、ちょいとエフェクトを付けたりするのが流行のようで。`` なのでppBlogでも画像ポップアップをパワーアップさせました。かといって過剰な演出はあまり好きではないので、そんなに凝らずに、これだけは備えておきたいというものにしています。`` `` 昨今のブロードバンドの普及に伴い、表示サイズの大きな写真を圧縮せずにそのままアップするケースも増えてきたように思います。結果、パソコンの解像度によっては、そんな画像を表示させるとブラウザからはみ出してしまうこともあります。なのでこのあたりを考慮して、ブラウザの枠からはみ出してしまうような大きなサイズの画像は2段階のポップアップとしました。まず、ブラウザ画面にフィットするような表示段階があって、で、さらに「実寸大アイコン」をクリックすると、元のブラウザからはみ出すような画像を表示させるというものです。`` 具体的にアクションを見たほうが分かりやすいでしょう。なお、画像は、National Geographicのサイト にあったサイズが大きめの写真を拝借してます(1024x768ピクセル)。効果を確認するには、ブラウザのサイズを1024x768ピクセルより小さくしておいて下さい。このサイトには秀逸な写真がたくさんあって、個人的にお気に入りの写真は、スクリーンセイバー用にダウンロードしたりしてます。`` `` 余談になりますが、このナショナルジオグラフィックの雑誌(日本語版もあります)には、新しく見つかった「ユダの福音書」の驚くべき解読結果のレポートが載っています。近々「ダ・ヴィンチ コード」の上映が始まりますし、何とも絶妙なタイミングですね。歴史とは、勝者が創り出す日記みたいなもんです。` →http://nng.nikkeibp.co.jp/nng/feature/0605/index.shtml`` スタイルシートの話になりますが、Firefoxだと、写真のドロップシャドウが意図したように見事に実現されるのですが、IE6やIE7βでは、まだまだですね。IE7の正式版では、せめてこのドロップシャドウのCSSぐらいは出来るようになって欲しいもんです。|martin|1|1|JavaScript||
[102] => 1146740830|開発日誌|Ajaxでログイン認証| こんばんは。昨日のエントリーで、ログイン認証をAjax `で実現しようかと述べていたのですが、そうしました。流れとしては、``` ログインアイコンをクリックすると、その場でログイン画面を生成 ` IDとPWDを入力したら送信。このときにAjaxのPOSTモードで送信しますが、IDとPWDはJavaScriptで[g]MD5[/g]処理して送出されるので、セキュリティー的には安心です。 ` 正しいIDとPWDであれば、指定していた管理画面に遷移しますし、認証に失敗すれば警告が出ます。 ` ``てな感じです。Ajaxを使うことの利点は、わざわざログインページに移って、そこで認証して・・・という流れがなくなり、少ない手順でログイン出来ることです。これに慣れると、これまでのログイン手順が面倒に感じますよ。キモのスクリプトだけを抜粋しておきます。``function AjaxLogIn(){` var module = Ajax.cloneScript("js/md5.js");` if(module){` o("loginSubmit").disabled = true;` Ajax.post("admin.php", "mode=login&adminName="+MD5.$(o("adminName").value)` +"&adminPass="+MD5.$(o("adminPass").value)` +"&type=ajax",` function(to){` if(to.match(/¥.php/)){` d.write('<script type="text¥/javascript">window.location.href="'` +to+'";<¥/script>');` } else {` alert(to);` o("loginSubmit").disabled = false;` o("adminName").focus();` }` }` );` } else alert("md5.js module Not Loaded!");`} `` ダイアログ画面は、マックOSXっぽくアニメーション化してみました。まぁお遊びですが。。アニメーションといっても、単に上からにょろっと出てくるだけですが、この際に昨日紹介したループ関数メソッドを使ってみました。```var slideDown = function(ob){ob.style.top = (parseInt(ob.style.top)+10) +"px"};`slideDown.loop(1, 16)(IO); // IOは、ダイアログのこと` `` 1ミリ秒おきに、slideDownという関数を16回繰り返すという指定です。興味がある方は、ソースをどうぞ。`` あと、追記ですが、上述のMD5関数は、Masanao Izumoさんのmd5.jsを圧縮したものを使用しています。` →http://www.onicos.com/staff/iz/amuse/javascript/expert/md5.txt`` 有用なスクリプトを公開して下さっている同氏に感謝します。|martin|1|1|JavaScript||
[103] => 1146608307|開発日誌|JavaScript周りのことをば| おはようございます。最新版のリリースに向けて、近頃はそれなりに時間を充てています。ppBlogでは、JavaScriptはかなり重要な位置を占めています。一応、JavaScriptオフでも閲覧には問題ないとは思うのですが、管理モードなどでは必須です。`` で、ppBlogでの主要なJavaScriptライブラリである、js/script.js の見直しを進めているところです。この中で、windowのonloadイベントには、いくつかの関数を割り当てています。これまでは、``addEvent(window, "load", function (){` roundedStyle();` quotedStyle();` initCSSHover();` if(moz) hackFirefoxToolTip();`});` ``でしたが、これだと、HTMLのDOMエレメントのみならず、外部リンクや画像やらも読み込んだ後でないと発動しません。画像など読み終えてなくても、DOMエレメントを読み込んでパースした時点で動く関数などはさっさと動いて欲しいものです。このようなことは誰もが思っているみたいで、JavaScriptマスターのDean Edwardsは、Firefoxに DOMContentLoaded という隠し属性みたいなやつを見つけて、それで、ごにょごにょやっています。→ The window.onload Problem - Solved! `` でも、個人的には、あまりスマートな方法には見えないんで(IE向けには外部スクリプトを別に用意しないといけないし)、自分なりにも考えてみました。そもそも、IEにある[g]document.readyState[/g] みたいなやつが標準で提供されていれば、みんな悩まずに済むのだけれど、ないから仕方なし(IEでも、挙動不審なところがあるようだし)。`` で、原始的な方法ではあるが、DOMエレメントの数を取得する d.documentElement.getElementsByTagName("*").length をミリ秒単位で監視しておき、それがプラトーに達した時点を読み込み完了とするというアプローチでスクリプトを書いてみた。こんな感じ。```DOM = {` ready : false,` size : d.documentElement.getElementsByTagName("*").length,` check : function(){ DOM.ready ? DOM.onload() : DOM.update.await(100)(DOM.size); },` update : function(i){` if(d.documentElement.getElementsByTagName("*").length==i){` DOM.ready = true;` DOM.onload();` } else {` DOM.size = d.documentElement.getElementsByTagName("*").length;` DOM.update.await(50)(DOM.size);` }` },` onload : function(){}`}`DOM.check();` `` あまり深くは考えていないけど、これで期待通りの動作をしている感じ。このサイトのppBlogでは、先ほどのwindow.onload のイベントを、こっちに割り当てて、```DOM.onload = function(){` roundedStyle();` quotedStyle();` initCSSHover();` if(moz) hackFirefoxToolTip();`}` ``というふうにしています。このやり方だとブラウザを選ばなくてベターではなかろうか。アイコン画像なんかを全部表示していなくても、DOMツリーを読み込んだ時点で発動します。エドワーズのとこにあるデモのスクリプト(http://dean.edwards.name/my/busted.html)に似せて同じことをDOM.onload で実現したサンプルを載せておきます。→http://p2b.jp/demos/busted.html`` ちなみに、Functionオブジェクトに、新たにawait というメソッドを定義してそれを使っています。まぁ普通にsetTimeout でやれば良いのだけれど、勉強がてら。JavaScriptマスターである最速インターフェース研究会さんのエントリーを参考にしました。→ Function.prototypeを拡張して遅延実行を実現する `` まだよく理解していないので違うかもしれないけれど、このawait メソッドをまねて、loop というのを定義しました。正しいのかな? 狙いとしては、limitで指定した回数だけ、msミリ秒おきに関数を実行するというやつです。```Function.prototype.loop = function(ms, limit){` var count = 0, self = this;` return function(a){` if(limit <= count) return;` count++;` self.await(ms)(a);` arguments.callee.await(ms)(a);` }`}` `` 今のところppBlogでは、これは使っていないけど使うかもしれない。簡単な例としては、``var func = function(v){alert(v);}`func.loop(1000,3)("1秒おきにアラートを3回表示"); ``とか。`` あと、ログインの際にAjax を使って、少しだけログインの手順を減らすというのを考えています。その際にAjaxのPOSTメソッドでユーザー名とパスワードを送信するのですが、このままだとセキュリティー的に気持ち悪いので、MD5で暗号化してから送信するようにする予定です。大まかな動作は確認出来ています。とりあえず。(あぁ、コメント数がマイナスになるのも直さないと・・・)|martin|1|1|JavaScript||
[104] => 1145534785|開発日誌|アクセス解析の暫定版|こんばんは。フォーラムで、アクセス解析にあるYahooエンジンの「検索語」が文字化けしているというご指摘がありました。原因のひとつにログファイル自体の文字コードが統一されていないこともあるので、この際、UTF-8でログも統一するようにした暫定版をアップしておきます。ログの文字コードをUTF-8に決め打ちして、現在のログとの互換は考慮していません。なので、現在のログは手元にダウンロードしておくなりしておいた方が良いかもしれません。この新しいやつを使ってみたいという方は、4月分のログに関しては、適当に保存後、FTPソフト上で削除しておくと、新しいログと古いログとがごっちゃにならずに済みます。`` 最終的には、現状、ログはひと月に1ファイルですが、これだとアクセスに応じてログサイズが肥大するので、あるサイズ以上になれば分割するなどの処理も必要だなぁと思っています。` ` なお、ブラウザのアイコンもいくつか増やしました。マックOS XにはSafari以外にも「シイラ Shiira」なんていうお洒落なブラウザがあるようで、それのアイコンも追加しています。以下にスクリーンショットを載せておきますね。` ` ` 検索エンジンのプラットフォームに、Wikipediaもあり、これ経由のアクセスがそれなりにあるので、このアイコンも追加してます。自分のサイトの「検索語アクセス」を見てみると、以前の書き込みで、IEのメモリーリーク問題について言及していたんですが、そのせいか、この検索語でのアクセスも目立ちます。あとは、当然ながら「ppBlog」でのアクセスは多いです。` ` ` 生データを見てみると、Mozillaならぬ「Monazilla」というのもちらほらとあり、これは2ちゃんねる専用ログ巡回ソフトのようです。これのアイコンも追加してます。` ` ` これから先は余談なんですが、グーグルの検索語を表示する際に、たまに文字コードの変換エラーが出るのがあって、生ログを調べてみると、なんと、文字コード指定の「ie=UTF-8」の部分が「ie=UFT-8 」になっているじゃないですか。しかも、これはグーグル本家(google.co.jp)が間違っているのです。何故なら、UTF-8をフルスペルで書くと、8-bit UCS Transformation Format ですから。証拠を載せておきます。``このために、スクリプトの中で、`if($enc=='UFT-8') $enc = 'UTF-8'; `という何ともトホホな処理を入れています。まぁ、そのうち修正されるのでしょうが。UFTと言えば、医療の現場では、ウラシルとテガフールの合剤である抗がん剤のことで、大腸ガンなど種々のガンの治療に使われています。UFTカプセルという経口の抗がん剤が出来たことで、患者さんの負担も随分 軽減したと思います。`` さらに余談ですが、今日グーグルで調べ物をしていると、グーグルのロゴが変わっているのに気付きました。なんだかミロっぽいなと。そこでピンと来て、[w]ホアン・ミロ[/w]について調べてみると、案の定、4月20日はミロの生誕日なんですね。しかも、最近は「ホアン」じゃなくてより現地語に近い発音の「ジョアン」ということも知り。グーグルの社員にきっとミロ好きがいたんでしょうね。こういう余興大好きです。このロゴは今日(4月20日)だけかもしれないので、記念にこれも載せておきますね。しかし、見事にミロっぽい。`` ``[file:1145534785_stat_EUC.zip:48.9/]|martin|1|1|JavaScript||
[105] => 1138720143|開発日誌|RC1アップ|とりあえず、EUC-JP版とUTF-8版をアップしました。何だか、久しぶりに取り組んだので自分でも忘れている部分(関数の定義とか)などあり、作業を思い出すのが大変だったり。もうちょっと気合を入れねば。`` てなわけで、インストーラーは、RC2 で付けようと思います。1.5ベータと比してそれほど変わってはいないと思うのですが、新機能としては、コメントやトラックバックの際の「NGワード」を付けたことでしょうか。管理画面の「IPコントロール」から設定できます。1.5ベータをお使いの方は、最低限、```onwer/ini.inc.php `owner/ngwords.inc.php(←今回新しく追加になった) `admin.php `trackback.php `modules/ 以下全部 `js/ 以下全部 `css/ 以下全部 ` ``を上書きすればいいのではと。なお、ini.inc.php では、管理者名とパスワードなども設定しているので、上書きする際には、予め、この部分を書き換えておくと、そのままログイン出来ます。初期設定では、``ID:admin`PWD:pass ``になっているので、そのまま上書きした場合は、これでログインして、自分のやつに変更できます。`` 上のように、逐次上書きというのは、漏れもありそうなので、確実なのは、``` RC1を新規にアップ ` 各ディレクトリのパーミッションを変更(これが一番キモです) ` ログやコメントログやトラックバックログ、PIXディレクトリの画像をそのまま移す ` 何か新規に記事を書き込めばキャッシュファイルが更新されるので、それでOK ` ``という流れでしょうか。` ` 細かいところで言えば、記事の編集時のテキストエリアの高さを広げたり、狭めたりするボタンを付けたり、テーマ切り替えメニューをプルダウン式からリスト形式(UL)に変えて、スタイルシートでお洒落に見えるようにしたりとか ギャラリーのスタイルシートを大幅に変えたりとか、色々変わっている所は変わっています。`` あと、UTF-8の場合、そのままログを移しても、文字コードが違うために確実に動きません 。文字コード変換スクリプトをそのうちアップしようとは思いますが、ちなみに自分は、フリーソフトの「KanjiTranslater 1.3 」を使いました。素晴らしいツールを提供して下さっているKASHIM.COMさんに感謝です。|martin|1|1|JavaScript||
[106] => 1138568927|開発日誌|今夜RC1リリース|おはようございます。このところ多忙につき、ppBlogの開発・サポートはまったく手付かずでしたが、今夜ppBlog1.5RC1 を出します。ほんとは、日曜深夜に出そうと思ったのですが、ちょくちょく中断があり進みませんでした。。なかなか都合良くは行かないものです。`` 小生のサポートが不十分にもかかわらず、有志の方々の援助もあり、ppBlogを使って下さる方も着々と増えており、このような状況を看過するわけには行きませんで。心を新たに、開発に励みたいと思います。ロードマップをば。``` 今夜RC1リリース ` 今週末〜来週RC2 ` 再来週 1.5正式版リリース ` `てなところです。これは、タイトに進んでいくのでは思っています。RC1における1.5のβ版からの変更としては、コメントやトラックバックでのNGワード対策も盛り込んでます。小生も実際に、トラックバックスパムを受け、これに対処したものです。これで、少なくとも小生が受けた海外からのスパムは完全にブロック出来ています。` あ、あと文字コードですが、従来のEUC-JP版に加え、UTF-8版も一緒にリリースします。|martin|1|1|JavaScript||
[107] => 1131336575|開発日誌|IEのメモリリーク問題|IEあるいはIEエンジンのブラウザ(Sleipnirとか)を使っていて、どうもページの描画速度が遅い気がする―もっと正確には最初にページを開いたときより 遅くなった―と感じたことはないだろうか? 特にあなたがJavaScript を多用したページを開いているならば、もしかしたらIE特有のメモリリーク問題([g]IE memory leaks problem[/g])が原因かもしれない。`` 余談ですが、前回のmoblogエントリーは、自分のブログにモブログしたつもりが間違ってこちらにエントリーしてしまいました。気が向いたら移動しておきます。`` で、本題ですが、この問題はより多くの利用者が(IEエンジンの)タブブラウザーを使うようになればなるほど顕在化してくると思われるのでメモしておこうと思います。ppBlogでもJavaScriptは欠かせませんし。最初に言っておきますが、この問題はIE4-6 に特有のもので他のモダンなブラウザは影響を受けません。`` では、早速、IE6単体で (タブブラウザではなく)このテストページ を開いて下さい。216色のカラーチャートを作成し、その各セルにマウスイベントを設定しているシンプルなデモです。ページを開いたらリロードを何回か繰り返してみましょう。生成時間がどんどん長くなっているのを確認したら、そのページを一度閉じて 、新たに次のテストページ を開いて同様にリロードを繰り返してみましょう。どうでしょうか?今度は生成時間が伸びていくということはありません。`` この2つのページの違いは何でしょうか?最初のテストページでは、まさにメモリーリークが起こっています。リンク先にも書いてありますが、分かる方はControl + Alt + Del キーを押して、タスクマネージャを起動、IEXPLOERE.EXE のメモリを見ながらリロードを繰り返せばメモリが肥大化していくのを見ることができます(尚、ウィンドウを閉じればメモリは開放されます )。この2つのテストページの違いは、ほんのちょっとしたことです。やや専門的になるかもしれませんが、イベントを定義する関数を定義しているのですが、その扱いの違いです。もともとは、Scott Andrew (最近は専ら音楽に夢中のようです。。)がW3CとIE特有のイベント定義関数の差を吸収するために作り出したaddEvent/removeEvent 関数ですが、オリジナルのままでは、IEのthis参照に問題があったために、様々なバージョンが編み出されました。ppBlog1.5βでも似たようなやつを付けていますが、ここに挙げるのはその改訂版です。まず、メモリリークを起こすやつから。```function addEvent(obj, evType, fn){` if(!obj["_"+evType]){` obj["_"+evType] = [];` if(obj["on" + evType] != null) obj["_"+evType].push(obj["on" + evType]);` obj["on" + evType] = function(e){` var e = e || window.event;` for(var i in this["_"+e.type]) this["_"+e.type][i].apply(this,[e]);` } ` } else {` for(var i in obj["_"+evType]) if(obj["_"+evType][i]===fn) return;` }` obj["_"+evType].push(fn);`};``function removeEvent(obj, evType, fn){` if(obj["_"+evType]){` for(var i in obj["_"+evType]){` if(obj["_"+evType][i]===fn) delete obj["_"+evType][i];` }` }`}; `` addEventの中で、匿名関数を使っています(ホナ トピンクの部分)。次にメモリリークを起こさないやつ。```function addEvent(obj, evType, fn){` if(!obj["_"+evType]){` obj["_"+evType] = [];` if(obj["on" + evType] != null) obj["_"+evType].push(obj["on" + evType]);` obj["on" + evType] = evokeEvent;` } else {` for(var i in obj["_"+evType]) if(obj["_"+evType][i]===fn) return;` }` obj["_"+evType].push(fn);`};``function removeEvent(obj, evType, fn){` if(obj["_"+evType]){` for(var i in obj["_"+evType]){` if(obj["_"+evType][i]===fn) delete obj["_"+evType][i];` }` }`};``function evokeEvent(e) {` var e = e || window.event;` for(var i in this["_"+e.type]) this["_"+e.type][i].apply(this,[e]);`}; `` 具体的に各オブジェクトにイベントを設定していく部分をaddEvent 関数の外に出していますね。おかげで関数が3つ になっちゃってます。世の中の多くのJavaScriptの書き手は、「スクリプトはシンプルなのがスマートだ」という理念を持っていて、自分もその一人です。その結果として関数内の匿名関数やクロージャーを多用する傾向にあります。悲しいかな、IEにはこれが通用しないのです。もっと詳しくこの問題を理解するキーワードは、「クロージャーclosure 」と「循環参照 circular reference 」です。ここで詳しく解説しようとは思っていないので悪しからず。以下のサイトを参照してください。Richard Cornfordのサイト が端的にこの問題を指摘しています。```The Internet Explorer web browser (verified on versions 4 to 6 (6 is current at the time of writing)) has a fault in its garbage collection system that prevents it from garbage collecting ECMAScript and some host objects if those host objects form part of a "circular" reference. The host objects in question are any DOM Nodes (including the document object and its descendants) and ActiveX objects. If a circular reference is formed including one or more of them, then none of the objects involved will be freed until the browser is closed down, and the memory that they consume will be unavailable to the system until that happens. `
` ````` この問題は、Microsoftも認識しているのでIE7では解決されると良いのですが。尚、上に挙げたサイトで、最後のMihaiのページもよくまとまっているのですが、Mihaiが例示しているメモリーリークの退避例でも、やはりリークが起こるような気がします。`` あと、メモリーリークを起こすページを検出するツールがあるので、これもリンクしておきます。もっとも、このツールは完璧ではなく、すべてのメモリリークを検出するわけではない ですが目安にはなるかと。メモリー負荷テスト(Blow memory)は、メモリーが増大していく様を見れるので有用です(もっともタスクマネージャーでも見れますが)。``Out of Hanwell:IEメモリリーク検出ツール ``タブブラウザが出てくる以前は、この問題はさほど気にすることもなかったかもしれませんが、タブブラウザでは、常に複数のページを開いているというのが当たり前ですし、AJAXの台頭で、これからもJavaScriptはwebページで多用されるでしょうから、この問題を認識しておくのも悪くはないと思います。自分みたいなプログラム配布者はなおさらです。`` あ、あと、スコット・アンドリューがaddEvent/removeEventについて最初に紹介したページを見付けたのでリンクしておきますね。` →http://www.scottandrew.com/weblog/articles/cbs-events|martin|1|1|JavaScript||
[108] => 1130917044|開発日誌|PHPに最悪の脆弱性 |PHP史上最悪の脆弱性(ぜいじゃくせい)が発見されたようです。まずすべき対策は、PHP4.4.1 以上にアップグレードすることのようです。が、多くの方は、独自でドメインを取っていても、レンタルサーバーなのでPHPのバージョンアップには手が出せないという状況だと思います。`` これは、暫くはサーバー会社なり管理人さんの反応を見るしかないですね。とにかく重大な脆弱性 らしいです。具体的な部分を自分のブログ に少し書きましたが、まだよく呑み込めていません。ppBlogのプログラム自体は、現時点では、怪しい箇所は思いつきませんが見直しておきます。|martin|1|1|JavaScript||
[109] => 1130174102|開発日誌|PHPでドロップシャドウ|最近のエントリーはアップデートばかりでバランスが悪いので、たまには開発日誌を書いてみよう。`` それなりにプロ意識を持ったデザイナー達がざわざわとエントリーしてそうなDeviantART のサイト。ここでは至る所で作品のサムネイル画像を目にすることができます。で、どの画像にもいい感じでドロップシャドウが利いていますね。ドロップッシャドウ自体はppBlogでも指定出来るのですが、このDeviantのサイトのように綺麗ではありません。何故なら、おそらくDeviantのサイトでは、個々のサムネイルの大きさに合わせて、動的に「影」を生成しているからです(おそらく。ソースを見た感じでの推論です)。ppBlogでは、サーバーへの負荷やパフォーマンスを考慮して、このアプローチは取っていません。何より、PHPでのドロップシャドウのプログラムは「何だかややこしそうだ」というのがありました。`` でも、画像ギャラリーのサムネイル画像で、ぜひともDeviantみたいなドロップシャドウを実現したくて勉強がてらスクリプトを書いてみました。こんな感じです。左上にある「エリア拡張ボタン」を押すと見やすいと思います。``function ImageDropShadow($from='', $output, $borderW=5){` $size = GetImageSize($from);` $tl_shadow = ImageCreateFromPNG("Images/top-left.png");` $offsetX = ImageSX($tl_shadow);` $offsetY = ImageSY($tl_shadow);` $br_shadow = ImageCreateFromPNG("Images/bottom-right.png");` $shadowX = ImageSX($br_shadow);` $shadowY = ImageSY($br_shadow);`` $canvas = ImageCreateTrueColor($size[0]+$offsetX+$shadowX+$borderW*2, $size[1]+$offsetY+$shadowY+$borderW*2);` ImageAlphaBlending($canvas, true);`` switch ($size[2]){` case 1 : $out = ImageCreateFromGIF($from); break;` case 2 : $out = ImageCreateFromJPEG($from); break;` case 3 : $out = ImageCreateFromPNG($from); break;` }` ` $bg_color = ImageColorAllocate($canvas, 255, 255, 255);` Imagefilledrectangle ($canvas, 0, 0, ImageSX($canvas), ImageSY($canvas), $bg_color);`` ImageCopy ($canvas, $out, $offsetX+$borderW, $offsetY+$borderW, 0, 0, $size[0], $size[1]);` // top left` ImageCopyResampled($canvas, $tl_shadow, 0,0, 0,0, $offsetX,$offsetY, $offsetX,$offsetY);`` $tp_shadow = ImageCreateFromPNG("Images/top.png"); // top` ImageCopyResampled ($canvas, $tp_shadow, $offsetX,0, 0,0, $size[0]+$borderW*2,$offsetY, ImageSX($tp_shadow),ImageSY($tp_shadow));`` $tr_shadow = ImageCreateFromPNG("Images/top-right.png"); // top right` ImageCopyResampled ($canvas, $tr_shadow, $offsetX+$size[0]+$borderW*2,0, 0,0,` $offsetX,$offsetY, ImageSX($tr_shadow),ImageSY($tr_shadow));`` $r_shadow = ImageCreateFromPNG("Images/right.png"); // right` ImageCopyResampled ($canvas, $r_shadow, $size[0]+$offsetX+$borderW*2,$offsetY, 0,0,` $shadowX,$size[1]+$borderW*2, ImageSX($r_shadow),ImageSY($r_shadow));`` $l_shadow = ImageCreateFromPNG("Images/left.png"); // left` ImageCopyResampled ($canvas, $l_shadow, 0,$offsetY, 0,0,` $offsetX,$size[1]+$borderW*2, ImageSX($l_shadow),ImageSY($l_shadow));`` $bl_shadow = ImageCreateFromPNG("Images/bottom-left.png"); // bottom left` ImageCopyResampled ($canvas, $bl_shadow, 0,$size[1]+$offsetY+$borderW*2, 0,0,` $offsetX,$shadowY, ImageSX($bl_shadow),ImageSY($bl_shadow)); `` ImageCopyResampled ($canvas, $br_shadow, $offsetX+$size[0]+$borderW*2,$offsetY+$size[1]+$borderW*2,// bottom right` 0,0, $shadowX,$shadowY,$shadowX,$shadowY);`` $bm_shadow = ImageCreateFromPNG("Images/bottom.png"); // bottom` ImageCopyResampled ($canvas, $bm_shadow, $offsetX,$offsetY+$size[1]+$borderW*2, 0,0,` $size[0]+$borderW*2,$shadowY, ImageSX($bm_shadow),ImageSY($bm_shadow)); `` ImageDestroy($tl_shadow); ImageDestroy($tp_shadow); ImageDestroy($tr_shadow);` ImageDestroy($l_shadow); ImageDestroy($r_shadow);` ImageDestroy($bl_shadow); ImageDestroy($bm_shadow); ImageDestroy($br_shadow);` ImageDestroy($out);` ` switch ($size[2]){` case 1 : case 3: ImagePNG($canvas, $output); break; // GIF and PNG ` case 2 : $out = ImageJPEG($canvas, $output); break; // JPEG to JPEG` }` ImageDestroy ($canvas);`} `` いやー、長い長い。メモ紙に模式図を書きながらでないと、とても頭の中だけでは無理でした。改良の余地はありそうですが、これをutils.php に組み込んで、画像ギャラリーのサムネイル画像はそれっぽいドロップシャドウ付きで表示できるようになりました。Deviantと違う点は、Deviantはサムネイル画像とは別に、背景に影を(動的に)用意しているのですが、この上に挙げた関数で生成される影はサムネイルと一体化しています。なので、一度サムネイル画像を作ってしまえばおしまいなので、サーバー負荷などを気にする必要もありません。`` 上のギャラリーアイコンをクリックして雰囲気を見てください。最初にしては、まぁまぁかなと。なお、ここのギャラリーは、まだ画像が少ないんでイマイチな感じですが、weblogの方は画像が揃っているので、なかなか見ごたえはあります→http://martin.p2b.jp/index.php?mode=gallery|martin|1|1|JavaScript||
[110] => 1127132479|開発日誌|新しいテーマを追加してみた|まだ細部の詰めが出来ていませんが雰囲気はつかめると思います。ちょいとシックな感じなので"ppBlog le chic" 。` ブラウザ画面をスクロールしても動かないトップのナビメニューは、もうひとつのテーマ「Basic」と同じようにモダンなブラウザ(FirefoxやOpera,Safari)ではCSS(スタイルシート)のポジションに関する指定`position: fixed; `を用いて固定していますが、最もメジャーなブラウザであるIE6はこの指定には対応していません。なので、IEだけには別にIE専用のスタイルシートを読み込ませることでこの固定座標を実現しています。このサイトの二つのテーマでは、2種類の異なる方法で固定してます。詳しくは後日書こうかと思います。` ついでながら、バギーなIE6ですが、画像のPNG形式がサポートしている透過アルファチャンネルにも対応していません。なので、このppBlogでもこれまで配布していたドロップシャドウ用の「影」画像は透過情報は省いてましたが、来年の夏ぐらいには出てくるであろうIE7では透過PNGをサポートするので、それをにらんで影の画像は透過PNGファイルにしてます。ただ、これだと相変わらずIE6では透過せずに何ともみじめな「影」になってしまうので、これもスタイルシート(+スクリプト)で、透過情報を保持するようにしています。これで記事の背景色が白以外でもきれいにドロップシャドウが実現されます。これも後日記事にしようかと思います。|martin|1|1|JavaScript||
[111] => 1126742200|開発日誌|Hello, World!|ここにppBlogの更新状況や開発日記を書いていけば良いかな。さっそくv1.5系とこれまでの1.4系とで新しくなったところを紹介してみます。`` カテゴリー毎にに固有アイコンを付けれるようになった。まだ調整中ですが。個人的に欲しい機能だったので。アイコンがひとつ加わるだけでも何か見栄えが違います(気のせい?)。 ` コメントの付いた記事では、Ajaxを使ってその場で動的に そのコメントを表示できるようになった。[g]Ajax[/g](えいじゃっくす?)とは詳しくはグーグルで検索していただくとして、簡単に言えば「JavaScriptを使って、ページを再読み込みすることなしに、サーバーとやり取りして部分的にページ内容を書き換える」 こと、と言えば分かりやすいだろうか。こうすると何が嬉しいって、欲しいデータだけをサーバーから取ってこれるので、データの転送量が少なくて済み、サーバーへの負荷軽減になる。またユーザーから見れば、ページ全体を再度読み込む訳ではないので、操作にある種の連続性が得られるというか、シームレスなブロッグ体験が出来るというか、ややこしくなってきたが、ま、そういうことである。実際に試してみると分かります。コメントボタンを押すと、ちょっと間を置いて、コメントが表示されると思います。予め読み込んで非表示にしている訳ではないです。この「間(ま)」が、また良い感じ(個人的には)。とはいっても、いまどきのブロードバンドでは殆ど待たされることはないと思います 。 ` 3つ目としては、記事ボックスのスタイルが、かなり自由にカスタマイズ出来るようになったこと。「良いブロッグ」の条件として、個人的には「デザイン」を外すことは出来ない。ある程度、ブロッグ書きに慣れてくると、今度は差別化を図ろうとデザインに拘りたくなる。日付の位置はこっち側だとか、いや「posted by?」は上に持ってきたい、などなど。なので、記事ボックスを構成するそれらをパーツ化して、細かい調整はスタイルシートで指定するようにしました。肝心の「記事ボックス」の雛形は、各テーマディレクトリにあるtemplate.html の中で指定するようにしました。これだと、テーマごとに、がらりとデザインを変えることが出来ると思います。と言いつつ、まだひとつしか作ってないんだけど。。 ` 見た目はそんなところでしょうか。内部的には結構変わっています。まず、セッション管理を独自のやつに変えました。session.class.php というクラスを作成して、それでログインなどを管理しています。パフォーマンス的にも悪くないのではと。 ` また、ブロッグの設置当初は、いろんなエラーが表示されまくりと言うのは、誰しも経験あると思いますが、このエラーハンドラーも独自のやつを用意しました。非常にシンプルなものですが。これのon/offは簡単に切り替えが効くようにする予定です。エラーが出る内は、有効にしておいて、収まってきたら無効にしておく、なんてことが可能です。開発者から見れば、細かいエラー表示は、デバッグの有用な情報となります。 ` |martin|1|1|JavaScript||
)
ppBlog official
エントリー 112 件中 1-5 件を
ボックス表示 ⇔
リスト表示
2011/11/7
カテゴリー » 開発日誌
久しぶりのカキコ。
静的リンクでの挙動を変えています。URLのパスに日付情報などを含ませるように。まだ、いじっている段階なので、色々と不具合があるだろうけれど、まぁ気にしないと。
日付情報がある以外には、現状、PermaLink用の英数文字からなる記事タイトルを別に指定できたのですが、これはそのまま取っておくとして、そうでない場合は、記事のタイトルがそのままブラウザのアドレスバーに表示されるような感じにしてます(静的リンクが有効な場合ですが)。今時のブラウザならエンコードされた長ったらしい英数字ではなくて日本語文字列をそのまま表示してくれるので。
— posted by martin at 11:45 am
Comment [0]
TrackBack [0]
2010/8/28
カテゴリー » 開発日誌
こんばんは、martinです。
ppBlogでは、アクセス解析画面に「記事アクセスランキング」が組み込まれていますが、最新版(まだ配布していませんが)ではこれに「
勢いランキング 」も追加しました。
従来のアクセスランキングでは、記事のレビュー数のみでの評価なので古いエントリーの記事が上位に来やすいです。これに対して、「勢いランキング」は、理論上は、一日あたりのレビュー数(平均)になるので、最近のエントリーでも上位に来ることが出来、なんとなく流行のトレンドみたいなものが見えてきて、興味深いです。
このサイトのサイドバーのメニューに「人気記事ランキング 」があります。このリンクでも、ほぼ同じ内容のものを見ることが出来るので、興味ある方はどうぞ。タブ切り替えにしてみました。限られたスペースで、多くの情報を見せることができるので、使いどころによっては良いですね。
2件のレスポンス [+]
— posted by martin at 06:49 am
Comment [2]
TrackBack [0]
2010/8/25
カテゴリー » 開発日誌 »
JavaScript
innerHTML に比べると、outerHTML を使う頻度はぐっと少ない。現状、IE と Safari , Chrome , Opera が対応していて、未対応はFirefox だけ。使用頻度が低いメソッドに対して、Firefox向けに、長々しいスクリプトを書くのもどうかねぇ、と思ってググってみたところ、ナイスな投稿がありました 。
sOuterHTML = new XMLSerializer().serializeToString(oElement);
確かに、これは理にかなってますね。outerHTML自体は、値の取得だけでなくて、設定も出来るんだけど、そういう場面はまずないだろうから、このgetterだけで十分ですね。
<div id="Here">Hello, <strong>really strange</strong> World !</div>
対して、
innerHTML なら
Hello, <strong>really strange</strong> World !
が返されるし、
outerHTML なら、
<div id="Here">Hello, <strong>really strange</strong> World !</div>
が返される。実装例としては、
function getOuterHTML(e) {
if(e.outerHTML){ // IE, Webkit, Opera
return e.outerHTML;
} else { // Firefox (, Webkit, Opera)
return new XMLSerializer().serializeToString(e);
}
};
あるいは、短く
function getOuterHTML(e) {
return e.outerHTML || new XMLSerializer().serializeToString(e);
};
とか。
outerHTML
Hello, really strange World !
実際には、Firefoxだと xmlns="http://www.w3.org/1999/xhtml" という属性が付加されるので、気になるようなら適宜省けば良いでしょう。
JavaScript
— posted by martin at 01:25 am
Comment [0]
TrackBack [0]
2010/8/23
カテゴリー » 開発日誌 »
JavaScript
簡易画像ギャラリーのテスト。タイトルのような場合、ひとつの画像をクリックして、拡大表示にした際に、ポップアップした画面の右端に矢印が表示される。それをクリックすると、同じ記事に含まれる次の画像を読み込む仕様。
特に画像キャプションが付いている場合は、それも表示されるので、写真を主体に見せたい場合なんかには、好都合だと思います。
JavaScript
— posted by martin at 11:39 pm
Comment [0]
TrackBack [0]
2010/8/13
カテゴリー » 開発日誌 »
JavaScript
ppBlogのoParts.jsにtweenアニメーションみたいな動きを取り入れてみました。まだ試作段階ですが、テーマ:Basicであれば、左側のサイドバーの展開や、ソーシャルブックアイコンで、ちょっとした動きをみることが出来ます。
写真のポップアップにも。
JavaScript
— posted by martin at 11:31 pm
Comment [0]
TrackBack [0]
エントリー 112 件中 1-5 件を
ボックス表示 ⇔
リスト表示
Created in 0.0228 sec.
日 月 火 水 木 金 土
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Comments