[ カテゴリー » 開発日誌 ]

ppBlogへのしぃペインターの組み込み

category-icon

 こんばんは。お絵かきツールであるしぃペインターをppBlogに組み込むテストです。

 手順は以下の通り。
  1. しぃペインターの配布サイトLink からsptr_all1114.zipを入手する。
  2. ppdraw.phpspainter_all.jar(しぃペインターで必要なのはこのファイルだけ)をサーバー上のトップディレクトリにアップロード。
  3. upload.phpwrite.inc.phpedit.inc.phpをお絵かき用のものへ更新する。

 以上の手順を踏むと、以下のようなボタンが、書き庫画面に現れます。

ppdraw2

 このボタンを押すと、下図のようなしぃペインターのお絵かき画面が出てきます。適当に絵を描いて、しぃペインターの「投稿」ボタンを押すと、普通にppBlogで画像をアップロードした時のような画面になるので、後はいつも通りです。

ppdraw

 下の絵は、これで描きました。投稿の幅が拡がって良いかなと思います。

ppdraw0402232222
マウスで適当に描きました。

 これらのファイルを添付しておきます[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]か

 しぃペインターのモード(通常版かプロ版か)を指定出来ます。最初は、通常版の指定です。こちらの方が分かりやすいかなと思いますので。しぃペインターの使い方については、以下のリンクが詳しいです。

しぃペインターの使い方(しぃペインター講座)Link

添付ファイル: ppdraw.zipattachedIcon 

— posted by martin at 06:24 am   commentComment [4]  pingTrackBack [0]

VMLやSVGを用いた角丸コーナー

category-icon

 おはようございます。時間があるときに、以下のようなサイトを作成しているのですが、この2枚のスクリーンショットは、違うところがあります。どこが違うのかというと、2枚目のやつは、ボックスのコーナーが丸っこくなっていて、いわゆる角丸コーナーと言われるものになっています。

shot1

shot2
こっちの方がパリっぽい!?

 ちょっとお洒落っぽいサイトデザインにしようと思っているのですが、そのためには、角張ったデザインよりも、角が取れたデザインの方が良いかなと考えました。で、角丸コーナーは、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を使うにしても、もうちょっと、凝ってみることにします。そもそも角丸コーナーを実現するには、以下のようなアプローチを取るのが自然でしょう。

principle
この考えでいけば、Firefoxなどのradiusと同じ値を指定できるだろう。

 要は、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で見ると、以下のように見えます。なかなか良い感じですね。

shot3

 残りの角についても同様にすれば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指定した要素に対して角丸を発動していますが、特定のクラス名を持ったものに対して、ということも簡単に出来るでしょう。

どのブラウザでもほぼ見た目が同じな角丸コーナーのデモLink

 上のサンプルでは、ついでにFirefoxやWebkit系でも、スクリプトでボーダー属性を指定するようにしています。このふたつ、指定の仕方が微妙に違うんですよねぇ。ちょっとはまりました。以下の感じ。
document.getElementById(id).style.WebkitBorderTopLeftRadius = radius + "px"; // Webkit系
document.getElementById(id).style.MozBorderRadiusTopleft = radius + "px"; // Firefox。leftのLも小文字。

 なお、OperaでのSVGの使い方は、「Operaで丸角を実現するCSSを試してみた (解決)Link 」や「角丸にするためにライブラリを作ってみるLink 」が参考になりました。

— posted by martin at 01:15 pm   commentComment [0]  pingTrackBack [0]

ppBlogをサーバー上でZIP展開

category-icon

 こんばんは。どうも昨日辺りから自宅のネット接続がとろいです。ppBlogは、ファイル数は390個(決して多くはないと思いますけど)近くあるのですが、それが昨日は全部アップロード出来ずじまい。愛用しているFFFTPGの転送画面が何度も途中でフリーズしたようになってました。昔、28.8kbps?ぐらいのモデムでピーガラガラとかやってたのを思い出しはしませんでしたが。

 というわけで、ブログシステムというものは、多機能になればなるほど、当然のようにそのサイズが肥大化していきます。なので、サーバー上に、圧縮されたZIPファイルをさくっとアップロードして、そこで展開するのが楽だよなぁ、と思ったので、PHPの充実したオンラインマニュアルを片手に、そういうスクリプトを書いてみました。最初に書いたのが以下です。ローカルのテスト環境でわけなく作動したので、こりゃいけるとサーバー上で試したら、zip_open関数がないと怒られました(--)

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がないことには・・・。

添付ファイル: ppblogunzip.phpattachedIcon 

— posted by martin at 03:58 am   commentComment [0]  pingTrackBack [0]

正規表現を使わないCSS3対応の「属性限定」セレクタ関数

category-icon

 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さんLinkエントリLink [latest log]が非常に参考になりました。

CSS3の「属性」セレクターをほぼ網羅していると思いますが、とりあえずhttp://mootools.net/slickspeed/Link にある属性セレクターはすべてパスします(ただし、div[class!=made_up]は、CSS3にはなさそうなので未対応)。

 上のソースコメントをみれば分かりますが、キャッシュを有効にするとより速くなります。でも別になくても良いかなと思ってます。細かい点を言えば、A要素のREL属性なんてのは、大文字小文字を区別しないようですが、そこまでは追ってません。要は、ppBlogで動けば良いので。

 ppBlog1.8.0での実装は、上のソースをベースにしたものになっています。

— posted by martin at 09:11 pm   commentComment [0]  pingTrackBack [0]

テキストエリアの自動リサイズ再び

category-icon

 以前、テキストエリアのサイズを文章の長さに合わせて変えるスクリプトを考えて、それをppBlogのエディタにも採り入れているのですが、それは意図した様に動くには動くのですが、えらく力業なスクリプトでした。その恥ずかしいスクリプトは、ここLink に置いてます?;w)

 記述も長くてスマートでないし、もっと簡単に出来ないかなぁと考えてみましたが、要は、自動調節というのは、テキストエリアのスクロールバーが表示されなくなるまでエリアを伸ばすということなので、その考えで行けば簡単でした。以下のような記述でいけますね。

function autofit(el){
 if(el.scrollHeight > el.offsetHeight){
  el.style.height = el.scrollHeight + 'px';
 } 
}

element.scrollHeightで、目的のテキストエリアの、スクロール分も含めた高さ(+ボーダー幅)を取得できます。で、element.offsetHeightで、見た目の高さを取得できます。なので、スクロールバーが表示されている状態というのは、文章が長くて表示しきれない状態なので、じぁ、テキストエリアの高さをscrollHeightに合わせれば良い、ということになりますね。なんで、こんな簡単なことに気が付かなかったかなぁ。まず、このデモを見てみましょう。


 とりあえずは、これでよさげですが、もうちょっといじってみましょう。例えば、この文章をコピペして、元の文章の下に貼り付けると、表示領域からはみ出るので、自動的にスクロールバーが表示されると思います。なので、ここでもう一度「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();
}

 以下に、これを適用したものを付けておきます。上の関数との動作の違いが分かると思います。


 この関数をonkeyupなどのキーイベントと結びつけておけば、入力に合わせて自動的にサイズが変わるテキストエリアの出来上がりです。これのデモを以下に挙げておきます。

 →http://p2b.jp/demo/autofit-textarea.htmlLink


— posted by martin at 05:30 am   commentComment [2]  pingTrackBack [0]

T: Y: ALL: Online:
Created in 0.0218 sec.
prev
2017.5
next
  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 30 31