27 Ağustos 2012 Pazartesi

Dojo (CoffeeScript) projesini MVC yapısına uygun geliştirmek

Önceki yazıda aşağıdaki uygulamayı Nginx+Tornado Server ile sunmak için kullandığım dosyaları paylaşmıştım. Daha önce de basit bir panele bir açılır düğme yerleştirmiştim. Şimdi işi biraz büyütüp MVC havası katıyorum ve bir form oluşturuyorum.





Özellikle baseUrl: tanımlamasına ve yollar için app/ kullanıldığına dikkat edin.

main.coffee
require { baseUrl : "/static/app" }, [ "dojo/dom",  "app/mainPanel" ], ( dom) ->

    #Bir panel oluşturuyoruz
    panel = new app.mainPanel()

    #Panelin DOM yapısını köke yani HTML BODY'e ekliyoruz
    dojo.body().appendChild(panel.domNode)

    #Tarayıcılar standart HTM özelliklerine göre yerleşimi yaptı
    #Ama Dojo nesneleri yerleşimler için özel değişkenler kullanıyor
    #Herşey hazır olduğunda, dojo'nun kendi özelliklerine uygun yerleşimi yapmasını istiyoruz
    panel.startup()



mainPanel.coffee
define \
    ["dojo/_base/declare", "app/mainPanel_ui", "dojo/domReady!"],
    (declare) ->




        #declare İfadesini Python ve C++'deki Class gibi düşünebilirsiniz, bir tür sınıf oluşturuyoruz, bir prototip
        #declare İfadesi ile tanımlanan yapılar global olarak erişilebilir oluyor
        #app.mainPanel_ui Sınıfından miras alıyoruz
        declare "app.mainPanel", [app.mainPanel_ui],



mainPanel_ui.coffee
define \
    ["dojo/_base/declare", "dijit/_WidgetBase", "dijit/layout/BorderContainer", "dijit/layout/ContentPane", "app/userModule", "dojo/domReady!"],
    (declare, _WidgetBase, BorderContainer, ContentPane) ->




        #Global erişim için app.mainPanel_ui kullanılacak, BorderContainer'den miras alıyoruz
        #böylece nesnemiz bir BorderContainer kopyası oluyor
        #Miras alınanlar ve bu sınıfa ait değişkenlere this nesnesi ile erişilebiliyor
        declare "app.mainPanel_ui", [BorderContainer],




            #Yapıcı fonksiyon kullanılabilir
            constructor: () ->
                this.design = "headline"
                this.baseClass = ".dijitReset"
                this.style = "overflow:hidden; color:white; border: 0; background-color:#333333; width: 100%; height: 32px; "

                #Menüyü tanımlıyoruz
                this.menuContainer = new ContentPane(region:"center",  style: "overflow:hidden; ",  \
                    content:"menü1 | menü2 | menü3 | menü4")

                #Kullanıcı işlemlerini yapacak modülü tanımlıyoruz
                this.user = new app.userModule()




            #DOM Nesneler oluşturulduktan sonra tanımladığımız nesneleri DOM'a ekleyebiliriz
            postCreate:() ->
                this.addChild(this.menuContainer)
                this.addChild(this.user)



Uygulamanın bölümlerini kullanıcı arayüzünü oluşturacak ve işlevleri yürütecek iki ayrı yapı olarak tanımlayıp görsel arayüzü işlev yapısına miras alınan nesne olarak bağlıyorum. Olayları da /dojo/on işlevi ile bağlıyorum.

userModule.coffee
define \
    ["dojo/_base/declare", "dojo/on",  "app/userModule_ui",  "dojo/domReady!"],
    (declare,event) ->




        declare "app.userModule", [app.userModule_ui],




            constructor: () ->
                #dojo/on İşlevi ile nesne olaylarını işlevlere bağlayabiliyoruz
                event(this.login_button, "click", this.onButtonClick)
                event(this.login_pass_lost, "click", this.onPassLostClick)




            onButtonClick: (evt) ->
                #Sunucuya bağlanıp kimlik kontrolü yapılacak
                console.log("login")




            onPassLostClick: (evt) ->
                #stack nesnesinin lostContent içeriği gösterilecek
                console.log("lost")


Kodu uzatmamak için sadece kullanıcı girişi formu oluşturdum.

userModule_ui.coffee
define \
    ["dojo/_base/declare", "dojo/on", "dojo/dom-construct", "dijit/form/DropDownButton", "dijit/TooltipDialog",  "dijit/layout/StackContainer",
        "dijit/layout/StackController", "dijit/layout/ContentPane",  "dijit/form/TextBox", "dijit/form/Form",
        "dijit/form/Button", "dijit/form/CheckBox", "dijit/layout/BorderContainer", "dojox/layout/TableContainer", "dojo/dom-geometry"],
    (declare, event, domConstruct, DropDownButton, TooltipDialog, StackContainer, StackController, ContentPane, \
    TextBox, Form, Button, CheckBox, BorderContainer,TableContainer, domGeometry) ->




        declare "app.userModule_ui", [ContentPane],




            constructor: () ->
                this.region = "right"
                this.style = "overflow:hidden"

                #Kullanıcı girişi
                this.login_form = new Form()
                this.login_container = new TableContainer(cols:1, labelWidth:"100%")
                this.login_uname = new TextBox(label:"Kullanıcı Adı :")
                this.login_pass = new TextBox(label:"Parola :",type:"password")
                this.login_uname_save = new CheckBox(label:"Beni hatırla: ")
                this.login_button = new Button( label:"Oturum Açma")
                this.login_pass_lost = new ContentPane( content:dojo.create("span", style:"cursor:pointer;", innerHTML:"Parolamı unttum") )
                this.login_container.addChild(this.login_uname)
                this.login_container.addChild(this.login_pass)
                this.login_container.addChild(this.login_uname_save)
                #Button'u ContentPane içine almazsak etiketi ayrıca yanında gösterecektir
                this.login_container.addChild(new ContentPane( content:this.login_button))
                this.login_container.addChild( this.login_pass_lost )
                this.login_form.domNode.appendChild(this.login_container.domNode)
                this.loginContent = new ContentPane( content:this.login_form)

                #Kayıp parola
                this.lostContent = new ContentPane( content:"Lost password")

                #Yeni kullanıcı kaydı
                this.registerContent = new ContentPane( content:"Register Form")

                #Kullanıcı bilgileri
                this.userContent = new ContentPane( content:"User account")

                #Taşıyıcı, düğme ve açılan diyalog
                this.stack = new StackContainer(style: "height: 200px; width: 400px;")
                this.userDialog = new TooltipDialog( content:this.stack)
                this.userButton = new DropDownButton(label:"Giriş yapın", baseClass:".dijitReset", dropDown:this.userDialog)

                this.content = this.userButton




            postCreate:() ->
                this.stack.addChild(this.loginContent)
                this.stack.addChild(this.lostContent)
                this.stack.addChild(this.registerContent)
                this.stack.addChild(this.userContent)


Çalıştırınca şöyle bir görüntü veriyor.


Ancak JS'in bir saçmalığı mı bilemiyorum olay bağladığım işlevlerde this nesnesi daima olayı oluşturan nesne oluyor, örneğin onButtonClick işlevi içerisinde this. nesnesi app.userMoudule olacağına login_button oluyor. Yani "object scope" konusunda bir saçmalık var, şükür ki Dojo ile bunun çaresi de var, onu da bir sonraki yazıya.

Hiç yorum yok:

Yorum Gönder