2010年6月23日水曜日

ExtJs-91 そろそろ平行してシステムっぽく(メモ)

CRUD系の実装がそろそろ終焉にむかっているので本を読みながら
もう一度ふりだしにもどって作っていこうと思う。

Omegaに頼る前に苦労しなきゃということで。。

■アプリケーションクラスについて
Property.
カレントのcategory
Categoryリスト

Method.
category change
Viewmode change

階層的に保持することで
アプリケーション、アプリケーション内種別、、
と言った管理にする。

■初期画面について
ロード画面は、windowクラスで、最小化、リサイズ、ドラッグをfalseに、modalで実装。
この時に表示する内容は、HTMLで静的にマークアップされたdivタグ。
500msのタイマはって、アプリケーションメインの初期化関数呼び出し。
この500msは、windowのアニメーション用のディレイタイマ。

■アプリケーションメインの初期関数
各パラメタの初期化、ui構築関数呼び出しと、初期画面用マークアップの削除getCmp.destroy()で実装。。
Qtipの初期化も。

■ui構築関数
Viewportの作成。
各リージョンの作成。
データの受け渡しはアプリケーションクラスを渡そうか?

ってことで。
またのんびり。

あれれ。sencha touchは??

2010年6月21日月曜日

ipadでリモートデスクトップ

いや、本題は
ipadでsencha touchのIFで開発中の画面を見たいなってなったんですが、
今の開発環境ってVisualStudioのダミーサーバ&ノート上のSQLServerで
ノートPCの閉じられた世界でやってたもので。。。ipadからは接続できず。。。

なのでもう半年とかそういうレベルで起動していなかったデスクトップを起動して
VirtualPCにWebサーバを構築した。
(以前とっておいたイメージファイルはどこにいってしまったんだろうか ・・・)

死ぬほどってわけじゃないけど、かなりセットアップ周りとかこのファイアウォールの
穴あけとかが嫌いなので概要をのこしておこう。
どうせまたいつか再構築したくなるんだろうし。
==========================
■サーバPCのセットアップ
VirtualPCへは
・.NETFramework3.5
・EnterpriseLibrary4.1
・WindowsInstaller4.5
・SQLServerExpress
と、、あとはVisualStudioWebなんたらをいれるだけ。
ジェネレータをいじくるのはノートPCだからWindowsAPを作る環境はいらないしね。
開発環境を入れるのはipadでリモートで開発とかできたらいいねぇということで。
これでサーバの環境はオーケー。
==========================
■DDNSへ登録
次にDDNSに自サーバを登録する。
むかーし登録してたはずだけど、当然、すでに有効期限は切れていて
再度登録。
いろいろあるね。こういうサービス、本当に感謝です。
==========================
■ルータの設定
あとは外部からの穴あけ。
HTTP
ICMP
リモート用のポートをあける。
※このサーバ機だけは静的なIP割り当てにしておいた。

pingうって確認。
(ICMPあけるの忘れてて、しばらく「あれーなんで通らんの?」とスタックしたorz)
==========================
■サーバの設定
再度VirtualPCに。
ファイアウォール設定です嫌いなんだよなぁ。なんか。

コントロールパネル→ネットワーク接続→「詳細設定」タブ→ファイアウォール設定ボタン

「詳細設定」タブ→ 
  ネットワーク接続の設定ボタン
   ↓
   「サービス」タブ→追加ボタン→・IPにサーバのローカルIP(静的にしたのはこのため)
                  ・内部、外部ともにDNS用ポート53を設定
                  ・で、DNSではUDPとTCP使うんでこの設定をTCPひとつ、
                  ・UDPひとつ。と計二つ追加する。
                  ・もちろんチェックを忘れずに。
                 →Webサーバ(HTTP)にチェック
                 →リモートデスクトップにチェック
  セキュリティログ(ログの設定を)
  ICMPの設定
   ↓
   エコーだけチェックした


この段階で
サンプルページをIISに設定してipadから自宅サーバに設置した
サンプルを参照することの確認が取れた。

あとはリモートデスクトップ。

==========================
■リモートの許可
 コントロールパネル→システム→「リモート」タブ
 「このコンピュータにユーザがリモートで接続することを許可する」にチェック

==========================

あとはipadのAppStoreでRemoteDeskTopLiteをDL

■Menu→EditConnectionで接続先設定を登録。
 IP address:DDNSに登録したIPを設定
 Port:リモート用にあけたポート番号
 ユーザ名:
 パスワード:
 っというところで
ほかはデフォルトでもOKかな。

=========================

うまくいきました。



   
  

2010年6月17日木曜日

ExtJs-90 フォームのidはmappingで解決。GridできてFormをつくって、レイアウトに入る前に。。

Ext-89での一件はmappingで対応した。Ext側は@kotsutusmiさんの
コメントからいただいてdataindexってことにしてフォームでの
登録もオーケー。


長かったなぁ。ここまで。
Gridは抽象化して実装とパラメータを切り分けられたし、共通部分の実装はおおむね完了。
Panelはこちらも抽象化してってGridの構造のままだけど、共通部分お実装はおおむね完了。

さて、
ここまでできたら次は
GridとPanelを結合しなけりゃ意味がない。


データに対して編集可能なGridを。
そんで、
パネル=検索条件=詳細な入力IFとして位置づけるため、
Gridとつなげてパネルから入力された条件で検索→Gridへ
GridでDblClick→パネルへ
っていう結合を実装する必要があるんだな。


■PanelのReadIFのキーはrowid(DB設計はすべてidentifierを持つようにして)で統一。

■検索条件とのつながり
Panelには検索ボタンをつけな
Panel→GridのLoadコールってことになる。

■詳細な入力IFとのつながり
ダブルクリック時にPanelのloadを行情報から取得したrowidを設定してPanelのLoad
をコールすればよいということになるわけで

Panel for search→Grid
Grid→Panel for Input

ってことになる。

でも、これ、関係を持つためにはお互いを知る必要が出てくる。
けど、相手を知るのはいやなので
それをくるむCRUDコンテナみたいなメッセージハンドリング用のクラスを
つくってそこに乗っけてみることにする。。
もう一年位前の勉強会で@kotsutsumiさんが教えてくれたやつの
縮小版みたいなイメージになるのかなぁ。。


あとはまたサーバサイドの実装になるわけで。。
特定の引数と比較演算子を対としたパラメータをクライアント側で用意するようにする。
デフォルトはANDでよいな。


もらった情報をWHERE句として生成するモジュールはあるからよし。
あとはほしいフィールド句を生成するモジュールを作ってあげて
それを内部で連結して問い合わせるストアドを作成すればおk。


もうチョイ。これを抜ければレイアウト!@kotsutusmiさん直伝、@ispernさん検証の
レイアウト。これやってみたい。

だからあとは、
やるってきめたらからやるリスト
・検索用のモードの設置
・Grid、Panelを結びつけるコンテナ作成
・(Panel for search)、Gridを乗せてみる
・Grid、 (Panel for input)を乗せてみる
・Panel for searchの条件実装
・Panel for searchからの条件ポスト実装
・Panel for searchからの条件解析→WHERE句実装(サーバ)

ExtJs-89 formの内コントロールのIDというかなんというか

grindのIDPropertyにあわせて
formのも実装すると'id'っていうnameのコントロールを設置することになるけーすがあり、
サーバサイドで受け取るとき、必然的に

reqid = Request.Form["id"];
こんな実装になる。
これじゃだめだ。


FormPanelのコントロールは未指定だと
ExtJs側でext-XXXX-XXXXという具合に
idを振る(これはコントロールID)



これが取得できちゃう。まぁ、そうだよな。。。


FormPanelはPanelとかとちがってPanelBodyがDIVではなくてFORMタグで実装されていてこのDOM(FORM)を利用する場合 は、from.getForm().submit()で操作します。
つまり、Formタグで送信するのでPanelの中に存在するものだけが送信されます。
って教えてもらいました。。


@kotsutsumiさん、またもや夜分に感謝です。


なのでデータ識別用のIDという名前とコントロール識別用の「ID」が重複する
ということになる。

回避策は。。。仕方なくForm時のサーバサイドの実装だけDBとは別にidってなまえじゃなくて
dataidとかにして別名にするかな。。。

めんどーだなぁ。仕方ないのかなぁ。

2010年6月16日水曜日

ExtJs-88 Senchaになりましたね

会社名がSenchaになったようですね。


http://www.extjs.co.jp/blog/2010/06/15/sencha-press-release/


jQtouchは知ってたけど、
Raphaelって知らなかった。

基本、JSの畑はExtJsな私にとって広すぎる。
興味だらけでおぼれますね。あー。

2010年6月10日木曜日

ExtJs-87 フォームはさくっと終了させたいなぁ

今日はジョギングしようと思ってたら子供の寝かしつけでぐっすりと。
ビール片手にコーディングです。

ExtJs86でフォームに搭載するコントロールの定型句は決めたので
あとは実装を。
Gridと同様、コントローラとモデルを「わざわざ」作ってあくまでFormPanelを実装から
切り離してみたかった。

で、モデルの基底クラスはこんな感じで固めた。
/// 
Ext.ns('Fwx.BasicCrud');
//abstract class
//config: class Config
//コンストラクタでinitializeメソッドコールすること。
Fwx.BasicCrud.FormModel = function () {
};
Fwx.BasicCrud.FormModel.prototype = {};
(function() {
    var me = this;
    me.form = {};
    me.configGenerator = {};
    //config:formpanel.getform()=Ext.form.Basicform
    me.initialize = function(config) {
        var me = this;
        me.configGenerator = config;
    };
    me.loadFailcallback = function(store, action, result, tran, r) {
        switch (action.failureType) {
            case Ext.form.Action.CLIENT_INVALID:
                Ext.Msg.alert('エラー', 'クライアントサイドでの異常。');
                break;
            case Ext.form.Action.CONNECT_FAILURE:
                Ext.Msg.alert('エラー', '通信エラーが発生しました。');
                break;
            case Ext.form.Action.SERVER_INVALID:
                Ext.Msg.alert('エラー', action.result.msg);
        }
    };
    me.loadSuccesscallback = function(r, options, success) {
        //Ext.Msg.alert('Failure', action.result.msg);
    };
    me.saveFailcallback = function(store, action, result, tran, r) {
        switch (action.failureType) {
            case Ext.form.Action.CLIENT_INVALID:
                Ext.Msg.alert('エラー', '入力されたフォーム情報に不備があります。');
                break;
            case Ext.form.Action.CONNECT_FAILURE:
                Ext.Msg.alert('エラー', '通信エラーが発生しました。');
                break;
            case Ext.form.Action.SERVER_INVALID:
                Ext.Msg.alert('エラー', action.result.msg);
        }
    };
    me.saveSuccesscallback = function(r, options, success) {
        Ext.Msg.alert('成功', '保存しました。');
    };
    me.deleteFailcallback = function(store, action, result, tran, r) {
        switch (action.failureType) {
            case Ext.form.Action.CLIENT_INVALID:
                Ext.Msg.alert('エラー', 'クライアントサイドでの異常');
                break;
            case Ext.form.Action.CONNECT_FAILURE:
                Ext.Msg.alert('エラー', '通信エラーが発生しました。');
                break;
            case Ext.form.Action.SERVER_INVALID:
                Ext.Msg.alert('エラー', action.result.msg);
        }
    };
    me.deleteSuccesscallback = function(r, options, success) {
        var me = this;
        Ext.Msg.alert('成功', '削除しました。');
        me.doReset();
    };
    me.doLoad = function(params) {
        var me = this;
        me.form.load({
            url: me.configGenerator.getFormAPIs().read,
            params: params,
            waitTitle: 'サーバ接続中',
            waitMsg: '読み込んでいます...',
            success: me.loadSuccesscallback,
            failure: me.loadFailcallback
        });
    };
    me.doSave = function(params) {
        var me = this;
        me.form.submit({
            clientValidation: true,
            url: me.configGenerator.getFormAPIs().write,
            params: params,
            waitTitle: 'サーバ接続中',
            waitMsg: '保存しています...',
            success: me.saveSuccesscallback,
            failure: me.saveFailcallback
        });
    };
    me.doDelete = function(params) {
        var me = this;
        me.form.submit({
            clientValidation: true,
            url: me.configGenerator.getFormAPIs().destroy,
            params: params,
            waitTitle: 'サーバ接続中',
            waitMsg: '削除しています...',
            success: me.deleteSuccesscallback,
            failure: me.deleteFailcallback
        });
    };
    me.doReset = function() {
        var me = this;
        me.form.reset();
    };
    me.setForm = function(form) {
        var me = this;
        me.form = form;
    };
}).apply(Fwx.BasicCrud.FormModel.prototype);


で、コントローラはこんなかんじだろうと。
Ext.ns('Fwx.BasicCrud');
//abstract
//config: { model: Model };
//コンストラクタでinitializeメソッドコールすること。
Fwx.BasicCrud.FormControl = function () {};
Fwx.BasicCrud.FormControl.prototype = {};
(function() {
    var me = this;
    //初期化処理
    me.initialize = function(config) {
        var me = this;
        me.model = config.model;
    };
    me.onSave = function(params) {
        var me = this;
        me.model.doSave(params);
    };
    //Loadイベントハンドラ
    me.onLoad = function(params) {
        var me = this;
        me.model.doLoad(params);
    };
    //Deleteイベントハンドラ
    me.onDelete = function(params) {
        var me = this;
        me.model.doDelete(params);
    };
    //Resetイベントハンドラ
    me.onReset = function() {
        var me = this;
        me.model.doReset();
    };
}).apply(Fwx.BasicCrud.FormControl.prototype);

動かせてないからなぁ。
これから継承した具象クラス作って。
サーバサイドをちょいちょい組んで。それから動作確認ってってあれ?24時。。

でももうチョイ。
これとGrid用とForm用のConfigパラメータクラスを作った。

Ext.ns('Owx.Crud');

Ext.ns('Fwx.BasicCrud');

//abstract
//config class for crud
Fwx.BasicCrud.Config = function () {};
Fwx.BasicCrud.Config.prototype = {};
(function() {
    var me = this;
    me.columnModelConfig = {};
    me.readerConfig = {};
    me.proxyAPIs = {};
    me.formAPIs = {};
    me.defaultRecord = {};
    me.extGridPanelConfig = {};
    me.extStoreConfig = {
        autoLoad: {},
        autoSave: {},
        proxy: {},
        reader: {},
        writer: {}
    };
    me.pageSize = 0;
    //TODO:
    me.getColumnModelConfig = function() {
        var me = this;
        return me.columnModelConfig;
    };
    me.getReaderConfig = function() {
        var me = this;
        return me.readerConfig;
    };
    me.getProxyAPIs = function() {
        var me = this;
        return me.proxyAPIs;
    };
    me.getFormAPIs = function() {
        var me = this;
        return me.formAPIs;
    }
    me.getDefaultRecord = function() {
        var me = this;
        return me.defaultRecord;
    };
    me.getExtStoreConfig = function() {
        var me = this;
        return me.extStoreConfig;
    };
    me.getExtGridPanelConfig = function() {
        var me = this;
        return me.extGridPanelConfig;
    };
    me.getPageSize = function() {
        var me = this;
        return me.pageSize;
    };
}).apply(Fwx.BasicCrud.Config.prototype);

Owx.Crud.BasicTableConfig = function() {
    var me = this;
    me.columnModelConfig = [
        { name: 'id', mapping: 'id', dataIndex: 'id', header: 'id', width: 100, sortable: true, hidden: false, hideable: true },
        { name: 'charCol', mapping: 'charCol', dataIndex: 'charCol', header: 'charCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.TextField(), allowBlank: true },
        { name: 'datetimeCol', mapping: 'datetimeCol', dataIndex: 'datetimeCol', header: 'datetimeCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.DateField() },
        { name: 'decimalCol', mapping: 'decimalCol', dataIndex: 'decimalCol', header: 'decimalCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.NumberField() },
        { name: 'ntextCol', mapping: 'ntextCol', dataIndex: 'ntextCol', header: 'ntextCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.NumberField() },
        { name: 'nvarcharCol', mapping: 'nvarcharCol', dataIndex: 'nvarcharCol', header: 'nvarcharCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.TextField() },
        { name: 'bitCol', mapping: 'bitCol', dataIndex: 'bitCol', header: 'bitCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.Checkbox()}];
    me.readerConfig = [
        { name: 'id', mapping: 'id', dataIndex: 'id', header: 'id', width: 100, sortable: true, hidden: false, hideable: true },
        { name: 'charCol', mapping: 'charCol', dataIndex: 'charCol', header: 'charCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.TextField() },
        { name: 'datetimeCol', mapping: 'datetimeCol', dataIndex: 'datetimeCol', header: 'datetimeCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.DateField() },
        { name: 'decimalCol', mapping: 'decimalCol', dataIndex: 'decimalCol', header: 'decimalCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.NumberField() },
        { name: 'ntextCol', mapping: 'ntextCol', dataIndex: 'ntextCol', header: 'ntextCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.NumberField() },
        { name: 'nvarcharCol', mapping: 'nvarcharCol', dataIndex: 'nvarcharCol', header: 'nvarcharCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.TextField() },
        { name: 'bitCol', mapping: 'bitCol', dataIndex: 'bitCol', header: 'bitCol', width: 100, sortable: true, hidden: false, hideable: true, editor: new ExtWrapper.Checkbox()}];
    me.formConfig = [
    //{ name:'id' , fieldLabel:'', width:, xtype:'', value:'', hiddenName:'', allowBlank:false},
        { name: 'id', fieldLabel: 'id', width: 100, value: '', hiddenName: '', allowBlank: true, xtype: 'ExtWrapperLabel' },
        { name: 'charCol', fieldLabel: 'charCol', width: 100, value: '', hiddenName: '', allowBlank: true, xtype: 'ExtWrapperNumberField' },
        { name: 'datetimeCol', fieldLabel: 'datetimeCol', width: 100, value: '', hiddenName: '', allowBlank: true, xtype: 'ExtWrapperDateField' },
        { name: 'decimalCol', fieldLabel: 'decimalCol', width: 100, value: '', width: 100, value: '', hiddenName: '', allowBlank: true, xtype: 'ExtWrapperNumberField' },
        { name: 'ntextCol', fieldLabel: 'ntextCol', width: 100, value: '', hiddenName: '', allowBlank: true, xtype: 'ExtWrapperTextField' },
        { name: 'nvarcharCol', fieldLabel: 'nvarcharCol', width: 100, value: '', hiddenName: '', allowBlank: true, xtype: 'ExtWrapperTextArea' },
        { name: 'bitCol', fieldLabel: 'bitCol', width: 100, value: '', hiddenName: '', allowBlank: true, xtype: 'ExtWrapperCheckbox' }
    ];
    //Grid時のAPI
    me.proxyAPIs = {
        read: '/Owx/__test/data/ReadList.aspx',
        create: '/Owx/__test/data/CreateList.aspx',
        update: '/Owx/__test/data/UpdateList.aspx',
        destroy: '/Owx/__test/data/DeleteList.aspx'
    };
    //Form時のAPI
    me.formAPIs = {
        read: '/Owx/__test/data/ReadForm.aspx',
        write: '/Owx/__test/data/CreateForm.aspx',
        destroy: '/Owx/__test/data/DeleteForm.aspx'
    };
    me.defaultRecord = {
        id: '',
        charCol: 'chardef',
        datetimeCol: '2010/10/10',
        decimalCol: '10.25',
        ntextCol: '長文フリーのデフォルトー',
        nvarcharCol: 'バーキャラノデフォルトー',
        bitCol: 'true'
    };
    //me.extGridPanelConfig = {};
    //me.extStoreConfig = {};
    me.pageSize = 40;
};
Owx.Crud.BasicTableConfig.prototype = new Owx.Crud.TableConfig();


こいつをまるっとぶち込めば
気持ちとしてはreconfigみたいなイメージで、実装とパラメータを切り離せた実装にちかずけたはず。。

コントロールの画面表示まではOK。

すごくいけてないけど、あとで何とでもなる。
詳細はWindowに載せるかなぁ。



しかし、ストレートで出してもかっこよく出るところがExtJsの好きなとこ。
やはり楽しい。

これで動作確認してパラメタだけをテーブル構成にあわせて作っていけば
最低限のCRUDを実装したシステムのガワができるはず。わくわく。
これでゼロからのスクラッチはなくなる。
フレームワークの拡張層ができる予定。
で、こいつを一通りシステムっぽくできたらOmegaに載せ変えて。
あと何ヶ月かかるんだろうか。
でものんびり楽しみだ。
それっぽくなりそうだ。

少し進んだ。
うーん、早く画面周りのエフェクトとかコントロールとかいろいろを触り触りたい。。。

2010年6月7日月曜日

Ipadだねぇ

先々月、世の中がipadって騒がれるちょっとまえに勉強会で触らせてもらったipad。

巡り合わせで、丁度wifi版が余った先輩が売ってくれるって話になり、
貯めてたお金で購入。
もちろん嫁ちゃんの稟議も通して。(勉強会直後、ものすごくアピールしてたから、すんなりだったけど。。)

数日使ってて思うことは、pgせんのであればこれ一台でok.
ということ。
ますますExtjsで自分のツール作って、ipadでアクセスな生活をしてみたく。

あーあと、資格本とかかさばるやつらを電子化ってのも吉。
ひとまず、コツコツたまーに参照するextjs本を電子化だ。
ってことでキンコーズに電話して詳細聞いてみた。
一応Webで確認はしてたんだけど。
断裁サービス、一回おおよそ250枚/105円だったかな。
と、scansnapも買えないんで、文書の電子化サービスについて聞いたら、一枚15円弱で。それも100枚以降は13円弱で。

こりゃたすかります、
ネタモトハ
http://www.ideaxidea.com/archives/2010/06/ipad_kinkos.html
で、ツイッターのRTで見た情報でした。

ほんと、良い気づき、良い発見、良い影響を頂きます。
いろいろと。

感謝です。

寝よー。