開発メモ,主に補足by子連れ親父プログラマー

2010-06-25

smartyの{section}関数に渡す配列は0から順番になってないと表示されない

smartyの{section}関数に渡す配列は0から順番になってないと表示されない 今見た感じバージョンはSmarty 2.6.18だけど。 以下のような{section}を使ったループ表示で、
{section name=key loop=$message}
 {$message[key]|escape}<br />
{/section}
php側を、
$message = array('123','456','abc');

$o_smarty -> assign("message", $message);
とすると、ちゃんと表示されるが、
$message[3] = '123';
$message[7] = '456';
$message[] = 'abc';

$o_smarty -> assign("emes", $emes);
とすると、何も表示されない。 悩まず、{foreach}に変更すべし。

2010-05-06

jQueryで作るタブのメニュー画面がリンクから飛んできた時も選択した状態にしたい

今開発してるシステムでちょっとおもしろそうな題材があったので紹介しておきます。
ソース全部載せると分かりづらいので一部だけで概念的に説明しますが、これはまあ、普通にレフトメニューがあって、そしてメインの部分にはタブでメニューを選択できるようなレイアウトの画面だと思って下さい。
レフトメニューはこんな感じ
<div class="left">
    <p>メニュー</p>
    <ul>
        <li><a href="sample.html#menu1">menu1</a></li>
        <li><a href="sample.html#menu2">menu2</a></li>
        <li><a href="sample.html#menu3">menu3</a></li>
        <li><a href="sample.html#menu4">menu4</a></li>
        <li><a href="sample.html#menu5">menu5</a></li>
    </ul>
</div>
メイン部分のタブはこんな感じ
<div class="menu-tab">
    <ul>
        <li><a href="#menu1" class="selected">menu1</a></li>
        <li><a href="#menu2">menu2</a></li>
        <li><a href="#menu3">menu3</a></li>
        <li><a href="#menu4">menu4</a></li>
        <li><a href="#menu5">menu5</a></li>
    </ul>
</div>
そして、このメイン部分のタブ表示の下に、以下のような、各タブをクリックした時に表示すべき内容を menu1 から menu5 まで全部並べておきます。
<div class="menu">
    <div id="menu1" class="list">
        menu1の内容
    </div>
    <div id="menu2" class="list">
        menu2の内容
    </div>
    <div id="menu3" class="list">
        menu3の内容
    </div>
    <div id="menu4" class="list">
        menu4の内容
    </div>
    <div id="menu5" class="list">
        menu5の内容
    </div>
</div>
これを jQuery を使って、menu2 のタブをクリックした時は <div id="menu2"> の内容だけを表示させ、かつ、
<a href="#menu2"> のタブには選択した状態のクラス(selected)をあてたい、しかもレフトメニューからのクリックでも同じ動きができて、レフトメニューはサイト内の他のページにもそのまま(同じまま)設置されるので、他のページから、
<a href="sample.html#menu2"> というリンクで飛んできた時にも menu2 の内容を表示したい、ということなんですね。

んで、最初に送られてきたソースがこんな感じでした。
$("div.list:not("+$(".menu-tab li a.selected").attr("href")+")").hide();
$(".menu-tab li a").click(function(){
    $(".menu-tab li a").removeClass("selected");
    $(this).addClass("selected");
    $("div.list").hide();
    $($(this).attr("href")).show();
    return false;
});
1行目で、クラスが selected になっている(=つまり選択状態)のタブの href 属性を取得して(この場合は #menu1 )、それ以外の $("div.list")、すなわち各メニューの内容を隠しています。
2行目でタブのクリックを取得して、クリックされたタブについてあれこれ処理しています。
3行目は全てのタブから selected クラスの除去。
4行目は選択されたタブに selected クラスを付加。
5行目は各メニューの内容を一旦全部隠して。
6行目でクリックされたタブの href 属性と同じ id のメニューの内容を表示。

このままでは確かにレフトメニューからクリックされた時も、このページに他のページからリンクで飛んできた時も動きません。
ということで、どうやって、<a href="sample.html#menu2"> の#以下の部分を取得するか、なんですが、とりあえず
location.hash
で取得できる、ということです。
あと、jQueryの .attr() の場合は単に、
.attr("hash")
でいけると。
今回の場合基本的に #menu2 という文字列がキーになっていて、あとはタブ部分のオブジェクトをなにがしか操作すればよさそうなので、メインの部分はこんな感じで。
$(function(){
    var selected_tab = location.hash;
    var link_tab = $(".menu-tab li a");

    tabchange(selected_tab, link_tab);

    $(".menu-tab li a, .left li a").click(function(){
        tabchange($(this).attr("hash"), link_tab);
    });
});
tabchange という function を別途用意することにして、それに #menu2 という文字列と、タブ部分のオブジェクトを渡してなんとかすることにします。
7行目は、タブをクリックしたか、あるいはレフトメニューをクリックしたか、で動かして、クリックしたリンクの .attr("hash") を渡す処理にしています。
ということで、function tabchange はこんな感じで。
function tabchange(selected_tab, link_tab){
    link_tab.removeClass("selected");
    link_tab.each(function(n){
        if ($(this).attr("hash") == selected_tab){$(this).addClass("selected");}
    });
    $(selected_tab).siblings().hide();
    $(selected_tab).show();
}
each とか、siblings とか使っちゃってますが、やってる内容は元々のやつと同じです。
一応完成っす。

2010-04-17

DISTINCT と ORDER BY を一緒に使う時の、PostgresとMySQLの違い

今やってるやつで、出てきた現象なのでちょっとメモ。
例えば items というようなテーブルがあって、id と name がある。
 id |  name
----+--------
  1 | test
  2 | sample
で、この items には複数のカテゴリーとサブカテゴリーが紐づけられている。
紐づけ用のテーブルは items_categories というようなもので、こんな感じになっている。
 item_id | category_id | sub_category_id | orders
---------+-------------+-----------------+--------
       1 |           1 |               1 |      2
       1 |           1 |               2 |      2
       2 |           1 |               2 |      1
アイテム1はサブカテゴリー1と2に、アイテム2はサブカテゴリー2に紐付いていて、どちらもカテゴリーは1だが、
そのカテゴリー1の中での並ぶ順番が orders ということで設定されている。
アイテム2が順番は1、アイテム1が2番と。

で、こいつをまず順番関係なしに、join してみると
SELECT ic.item_id, i.name 
FROM items_categories ic 
INNER JOIN items i ON ic.item_id=i.id
WHERE ic.category_id=1
こうなる。
 item_id |  name
---------+--------
       1 | test
       1 | test
       2 | sample
orders 順にしたいので、
SELECT ic.item_id, i.name 
FROM items_categories ic 
INNER JOIN items i ON ic.item_id=i.id
WHERE ic.category_id=1
ORDER BY ic.orders
とすると、
 item_id |  name
---------+--------
       2 | sample
       1 | test
       1 | test
これは動く。item_id が重複してるので、distinct を使うと、
SELECT DISTINCT ic.item_id, i.name 
FROM items_categories ic 
INNER JOIN items i ON ic.item_id=i.id
WHERE ic.category_id=1
ORDER BY ic.orders
Postgresの場合、エラーになる。
ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list
MySQLの場合、
 item_id |  name
---------+--------
       2 | sample
       1 | test
出る。
Postgresでも
SELECT DISTINCT ic.item_id, i.name, ic.orders 
FROM items_categories ic 
INNER JOIN items i ON ic.item_id=i.id
WHERE ic.category_id=1
ORDER BY ic.orders
とすればちゃんと出る。
 item_id |  name  | orders
---------+--------+--------
       2 | sample |      1
       1 | test   |      2
そりゃ、おかしいのはMySQLでしょう。この場合。

2010-04-13

デザイナーが作った.htmlファイルを一括して.tplファイルにする

find ./ -name '*.html' | while read line; do
mv $line `echo $line | sed -e 's,\.html$,.tpl,'`
done
いや、理解はできてない。。

2010-04-03

jQueryのWYSIWYGエディターでkeyupとかkeypressのイベントを取り出す

今週ずーっとやってた不毛なjQueryアプリですが、一番はまってたWYSIWYGエディター部分についてまとめておきます。
WYSIWYGエディターというと世間ではFCKeditorが有名ですが、まあ、あれはちょっと重いんじゃない?
ってことで、jQueryのプラグインで探す訳ですが、どーもね、これっていうのがない訳で。

最初に使ってみたのがこれ
LIGHTWEIGHT RICH TEXT EDITOR (RTE / WYSIWYG) PLUGIN FOR JQUERY

使い方はこんな感じ
<textarea name="info1" cols="100" rows="10"  class="rte1"></textarea>

<script type="text/javascript">
$(document).ready(function() {
 $('.rte1').rte({
  css: ['default.css'],
  controls_rte: rte_toolbar,
  controls_html: html_toolbar
 });
});
</script>
jquery.rte.tb.js にツールバーの設定がまとめられてるのでそれを編集する。
firebugで見てるとキーを入力する度に
!keyup イベントでは charCode プロパティの値には意味がないため使用すべきではありません。
の警告が出るのがいまいちです。

次がこれ
JHTMLAREA - WYSIWYG HTML EDITOR FOR JQUERY

使い方はこんな感じ
<script type="text/javascript">
$(function() {
 $("#info").htmlarea({
  toolbar: [
   ["bold", "italic", "underline", "|", "forecolor"],
   ["p", "h1", "h2", "h3", "h4", "h5", "h6"],
   ["link", "unlink", "|", "image"],
   [{
    css: "custom_disk_button",
    text: "Save",
    action: function(btn) {
     alert('SAVE!\n\n' + this.toHtmlString());
    }
   }]
  ],
  loaded: function() {
   //
  }
 });
});
</script>


<textarea id="info" cols="50" rows="15"></textarea>
loaded とかでエディターが起動した後になにか処理を入れられる。
ドキュメントがあまり詳しくなくていまいちですかねー。
Microsoft Public License というあまり聞いたことのない?ライセンスです。

最後にこれ
HTMLBOX

使い方はこんな感じ
<textarea id='hb'></textarea>

<script language="Javascript" type="text/javascript">
var hb = $("#hb").htmlbox({
    buttons:[
      ["separator_dots","bold","italic","underline"]
 ],
 icons:"default",
 skin:"green"
});
</script>
一応PDFのドキュメントがあるんですが、どうも説明が足りなくて使い方が分からない。
UndoRedoManager plugin とか。
おもしろそうなんだけど、さっぱりわからんのだー。

ま。最後のが一番よさそうですけどね。

で、今回の課題はこのエディターで文字を入力してる最中にそのイベントを取りたいってことなんだけども、
そもそもこういうエディターというのはフォームの textarea に設定するけれども、textarea そのものは非表示にして、その近くに iframe をつっこんで
<div>
 <iframe style="height: 305px; width: 415px;">
  <html>
   <head>
   </head>
   <body>
   </body>
  </html>
 </iframe>
</div>
みたいにして。

でhtmlを表示させて機能しているようで、DOMがどうなってるんだかさっぱり分からない。
どういうからくりになってるんだか・・・。

で、結論から言うと、
編集中の文字とかを取り出すには
$('iframe').contents().find('body').html()
keyupのイベントを取り出すには、
$('iframe').contents().keyup(function(){
 // なにか処理
}
でいけます。
試しに文字を入力する度にその中の文字数を表示するというのをやってみると、
<script language="Javascript" src="jquery-1.3.2.min.js" type="text/javascript"></script>
<script language="Javascript" src="htmlbox.min.js" type="text/javascript"></script>
<script language="Javascript" src="formState.js" type="text/javascript"></script>

<textarea id='hb'></textarea>
<script language="Javascript" type="text/javascript">
var hb = $("#hb").htmlbox({
 buttons:[
  ["separator_dots","bold","italic","underline"]
 ],
 icons:"default",
 skin:"green"
});

$(function() {
 $('iframe').contents().keyup(function(){
  $('#count').val($('iframe').contents().find('body').text().length);
 });
});
</script>
<input type="text" id="count" />
こんな感じになります。

2010-03-21

[見積システム:01]サイトマップ

最初にサイトマップくらい作っておこうってことで、作った。
かなりメニューが多くなってしまったが・・・。
見積もり編集のパターン選択のあたりのインターフェースをどうするか、まだ考えていないのでそこはちょっとまた後で直すことにして、とりあえず、おおまかにはこんな感じで行こう。

2010-03-20

gitを使ってデザイナーとの並行作業でテンプレートを修正する

テンプレートで修正が入った場合について、
例えば自分が作った index.tpl がこんなようなソースだったとする。
<div>
<h1>Colored Pencils</h1>
</div>
まずはコミットする。
$ git add index.tpl
$ git commit -m 'first commit'
ここで一旦リリースするが、その時にブランチを作っておく
$ git branch design_fix
その後なにか修正する。
例えば、以下のようにエラーメッセージの表示を追加した。
<div>
<h1>Colored Pencils</h1>
{$message|escape}
</div>
それをコミットする
$ git commit -a -m 'add message'
それを知らないデザイナーからファイルが届いた。
divにclass指定が追加になってる。
<div class="main">
<h1>Colored Pencils</h1>
</div>
作っておいたデザイナー用のブランチに移動して、
$ git checkout design_fix
この状態で、デザイナーが作った index.tpl をコピーしてからコミットする。
$ git commit -a -m 'design chenged'
再びマスターに戻り、マージする
$ git checkout master
$ git merge design_fix
以下のようにマージされた。
<div class="main">
<h1>Colored Pencils</h1>
{$message|escape}
</div>
ここでまたすかさず次のブランチを作っておくといいかもしれない。

問題なのは、デザイナーの修正が、以下のようなものだった場合、
<div>
<h1>Colored Pencils</h1>
<h2>12 colors</h2>
</div>
マージでエラーになる。
Auto-merging index.tpl
CONFLICT (content): Merge conflict in index.tpl
Automatic merge failed; fix conflicts and then commit the result.
そのindex.tplを見るとこんなんなってる。
<div>
<h1>Colored Pencils</h1>
<<<<<<< HEAD:index.tpl
{$message|escape}
=======
<h2>12 colors</h2>
>>>>>>> design_fix:index.tpl
</div>
message の行と h2 の行とどっちが上でどっちが下か分からないってことだろう。
以下のように順番を決めて編集保存して、
<div>
<h1>Colored Pencils</h1>
<h2>12 colors</h2>
{$message|escape}
</div>
コミットする。
$ git commit -a -m 'design fix'
無事マージされた
--- a/index.tpl
+++ b/index.tpl
@@@ -1,5 -1,5 +1,6 @@@
  <div>
  <h1>Colored Pencils</h1>
+ <h2>12 colors</h2>
 +{$message|escape}
  </div>

2010-03-18

MacPortsでOSXにphp5.3を入れる

OSXに、php5.3を入れようということで、
port installed
で見たところ、apache2とかはもうインストール済みになってるみたいだったので、もう一回以下のコマンドでphpのインストールに挑戦。
sudo port -d install php5 +apache2 +macox +mysql5 +pear +postgres +sockets +sqlite
最後に出た以下のメッセージを完全に見逃す
To customize php, copy
/opt/local/etc/php5/php.ini-development (if this is a development server) or
/opt/local/etc/php5/php.ini-production (if this is a production server) to
/opt/local/etc/php5/php.ini and then make changes.

If this is your first install, you need to activate PHP in your web server.

To enable PHP in Apache, run
  cd /opt/local/apache2/modules
  /opt/local/apache2/bin/apxs -a -e -n "php5" libphp5.so
こうして入れたシステム一式は、OSXの
/opt/local
の下に入るようです。
PHPのバージョン5.3.2になっている。
$ php -v
PHP 5.3.2 (cli) (built: Mar 18 2010 03:49:53) 
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
pearも入っている。
$ pear -V
PEAR Version: 1.9.0
PHP Version: 5.3.2
Zend Engine Version: 2.3.0
でアパッチを起動したいということで、
sudo launchctl load -w /Library/LaunchDaemons/org.macports.apache2.plist 
とりあえずこうするだけでapache動いた。
が、phpが動いていない。 そこで、以下を実行。
sudo cp php.ini-development php.ini
sudo /opt/local/apache2/bin/apxs -a -e -n "php5" libphp5.so
アパッチのhttpd.confに
以下を追加。
Include conf/extra/mod_php.conf
以下を付け足し。

    DirectoryIndex index.html index.php

で、
sudo /opt/local/apache2/bin/apachectl restart
したら、phpもオッケーに。
なったがな、しかし。だな。

2010-03-16

XAMPPのインストールと設定

Windowsのphpのバージョンを5.3.2にアップしようとしたらば、apacheまで動かなくなったので、もうあきらめて新規にXAMPPでインストールすることに。

apache friends

ここから XAMPP Windows版 1.7.3 をダウンロードしてインストール。

最初に環境変数に書かれている既存のMySQLとかphpのパスを消去してからやった方がよかったみたいですね。
既存のそれらのプログラムとごっちゃになってしまって、その修正に丸一日かかってしまった。
そもそもMySQLがサービスとして動いていたようで、XAMPPはそっちを見に行ってしまった模様。
マニュアルには最初に「セキュリティ」からMySQLのrootのパスワードを設定せよ、と書いてあるが、既存のMySQLを見に行ってるので既にパスワードがある状態になっている。
こりゃおかしい、ということで既存のMySQLのサービスを無効にして、環境変数の方は
C:\xampp\mysql\bin;
に書き換え、これでようやく正常に戻る。
改めて「セキュリティ」から進んで、rootのパスワードを設定。
あとphpMyAdminのDB接続設定をするために C:\xampp\phpMyAdmin\config.inc.php にrootのパスワードを設定
/* Authentication type and info */
$cfg['Servers'][$i]['auth_type']            = 'config';
$cfg['Servers'][$i]['user']                 = 'root';
$cfg['Servers'][$i]['password']             = 'password';
$cfg['Servers'][$i]['AllowNoPassword']      = true;
それからMySQLの文字コード関係設定。C:\xampp\mysql\bin\my.ini を開いて一番下に、
[mysqld]
skip-character-set-client-handshake
default-character-set = utf8
character-set-server = utf8
collation-server = utf8_unicode_ci
init-connect = SET NAMES utf8

[mysql]
default-character-set=utf8
を追加。

次にapacheの設定。
C:\xampp\apache\conf\httpd.conf を開いて、Directory の
<Directory />
    Options FollowSymLinks
    AllowOverride none
    Order deny,allow
    Deny from all
</Directory>
を以下に変更
<Directory />
    Options FollowSymLinks
    AllowOverride all
    Order deny,allow
    Deny from all
</Directory>
ついでにバーチャルホストの設定。C:\xampp\apache\conf\extra\httpd-vhosts.conf を開いて、
以下のコメントアウトを外す
NameVirtualHost *:80
一番下に以下を追加
<VirtualHost *:80>
    ServerAdmin someone@somedomain
    DocumentRoot "D:/project"
    ServerName project
    ErrorLog "logs/project-error.log"
</VirtualHost>
<Directory "D:/project">
    Options FollowSymLinks
    AllowOverride all
    Order deny,allow
    Allow from all
</Directory>
ここで、最後の Allow from が all になってないと見られないので注意。
さらに、C:\Windows\System32\drivers\etc\hosts を開いて、
127.0.0.1       localhost
127.0.0.1       project
を追加。
あと php.ini のこのヘンを修正
[mbstring]
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.http_input = pass
mbstring.http_output = pass
mbstring.encoding_translation = Off
mbstring.detect_order = UTF-8,SJIS,EUC-JP,JIS,ASCII
mbstring.substitute_character = none;
mbstring.func_overload = 0
最後にpearも既存のphpのパスが悪さしてへんてこりんな設定になっていたので、C:\xampp\php に go-pear を置いて、再インストール
php go-pear.php
これはコマンドプロンプトを管理者モードで実行しないとだめ。
あ、そうそう、あと、こうやってインストールした状態では、apacheの mod_rewrite は最初から使えるようになってるし、phpの short_open_tag はOffになってるぞ。

このブログを検索

Powered by Blogger.

ラベル

php (17) jQuery (13) OSX (10) MySQL (8) Javascript (7) Postgres (7) port (7) apache (6) Java (3) Smarty (2) html (2) pear (2) FCKEditor (1) XAMPP (1) css (1) git (1) perl (1) ruby (1)

Facebookバナー