2015年11月19日 星期四

dijit/form/ToggleButton

dijit/form/ToggleButton

簡介

dijit/form/ToggleButton 是一個介於按鈕 (Button) 和檢核框 (CheckBox) 之間的一個圖形介面。外觀是按鈕,行為卻像檢核框,其狀態只在 true 和 false 之間變化;而按鈕的標示也可以隨著狀態的改變而變化。和檢核框最大的不同是 ToggleButton 不接受 Form 或 Form Manager 的管控,因此不能透過後兩者去讀取或收集 TobbleButton 的狀態。因此,可以說 ToggleButton 比較像是個行為圖像,而非資料輸入用的圖像。
dijit/form/ToggleButton 繼承了 dijit/form/Button 。因此,在外觀、行為及屬性都和按鈕很像。第一次按下 ToggleButton 時,傳回值一律為 true;之後,每按一次,狀態便在 true 和 false 之間變化。

範例

範例中建立了三個外觀不同的按鈕,以展示一般 ToggleButton 在使用時,通常會具有的外觀。一個具有一般按鈕的外觀,一個只有圖像,最後一個按鈕同時有圖像和標示文字。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body{
    margin:0 auto;
    width:1000px;
    height:100%;
    padding-top: 20px;
}
</style>

CSS 中沒有特別的樣式需要設定。

HTML

<body class="claro">
    
    
    
</body>

HTML 中簡單的設定三個按鈕的掛載點。

Script


建立 ToggleButton 的方式和建立 Button 的方式非常類似,最大不同的地方在於 ToggleButton 多數時間在處理 onChange 事件,而非 onCkick 事件。而其作用的方式則和 CheckBox 非常類似,只在二個狀態間轉換。 ToggleButton 的狀態只有二種,就是 true 和 false。如果要知道目前是處於那一種狀態,可以用 var btn = register.byId("btn1"); btn1.get("checked"); 來取得目前的狀態;也可以用 btn.set("checked", "false"); 來設定狀態;這點則和 CheckBox 透過 "value" 不同。

2015年11月17日 星期二

dojo/_base/lang

簡介

dojo/_base 目錄下包含了眾多的模組,這些模組是整個 dojo 的基石,支撐著整個 dojo 的架構。其中的 dojo/_base/lang 基本上是一個用來擴充 Javascript 語言功能的一個模組。其所提供的函式多用在 Javascript 物件及物件屬性的操作上。 列示常用的函式如下:

  • exists()
  • setObject()
  • getObject()
  • clone()
  • mixin()
  • delegate()
  • hitch()
  • partial()
  • replace()
  • trim()

這段介紹三個函式:

exists(path, obj)
測試物件 obj 中是否存在著名為 path 的屬性。path 可以是由 "." 分隔的字串,dojo 會延著節點測試屬性值是否為 undefined,直到產生結果為止。若路徑最終的屬性存在時,傳回 true;若路徑中任一節點值為 undefined 時,則傳回 false。 obj 參數在沒有指定時,預設為全域變數 - window 物件。
setObject(path, value, obj)
設定物件中某一屬性的值,若路徑中有任一屬性節點尚未定義,則建立該屬性,一直到路徑中所有的屬性都存在後,將 value 指派給該屬性值。
getObject(path, boolean)
從全域變數 window 為起點,取得 path 路徑中的值。boolean 預設為 false,若路徑所指定的物件不存在,則傳回 undefined。當 boolean 設定為 true 時,,也用全域變數 window 做為路徑的起點,逐一建立路徑中的所有屬性後,最終傳回一個空物件 {}。

setObject() 和 getObject() 乍看之下,很像一般的 setValue() 和 getValue() 函式對。其實不然,setObject() 和 getObject() 兩者在用法上和傳入的參數,都有很大的不同,這點要特別留意。

Script


第 24 行的結果之所以會是 false,是因為在 function() 中(第 8 行)用 var obj 來定義 obj,因此 obj 只存在於 function() 中,並非 global 變數,因此不會加到全域變數 window 之下。第二個參數又沒設定,預設為 window。此時,window 下並沒有 obj 這個變數,因此傳回值為 false。
第 27 行的 getObject() 第二個參數值為 false,所以不會自動建立物件,因此傳回值為 undefined。 第 28 行的 getObject() 第二個參數值為 true,而路徑所指定的物件並不存在,所以會在全域變數 window 下自動建立該物件,並傳回一個空物件 - {}。

由第 29 行可以理解到第 28 行的物件己經被建立在全域變數 window 之下。

2015年11月10日 星期二

dijit/Tree

dijit/Tree

簡介

dijit/Tree 是將資料以樹狀結構的方法顯示在畫面上,其資料結構很類似作業系統中的檔案目錄結構。dijit/Tree 在使用時用到的模組還不算少,首先要有一個 dijit/store 中的模組來存放要顯示的資料;其次要有一個 dijit/tree/model 做為介面將存放在 store 中的資料餵給 dijit/Tree 模組; 如果 Store 中資料的改變要能即時反應在 dijit/Tree 中,要用一個 dojo/store/Observable 模組將 dijit/store 模組包起來,這樣當 Store 中的資料改變時, Observable 模組才能通知 Tree 模組在畫面上顯示變更的資料。

此外,在 store 中需實作 getChildren() 函式,傳回指定物件的所有子物件,這個函式在 store 中預設沒有提供。在 model 中則需實作 mayHaveChildren() 函式,這個函式得判斷指定物件是否有子物件存在,然後傳回 true 表示有子物件,傳回 false 表示沒有子物件。這個函式是用來判斷該物件的節點要使用什麼圖像來表示。

範例

在範例中,使用 dojo/store/Memory 將資料存放在記憶體中,再用 dojo/store/Observable 將 dojo/store/Memory 包起來;這樣,每當有資料變更時,才能通知 dijit/Tree 呈現變更後的結果。隨後建立一個 dijit/tree/ObjectStoreModel,這是因為範例中用的是 dojo/store/Memory,所以必須配合使用 dijit/Tree/ObjectStoreModel;如果用的是 dojo/data 中舊的 store 模組,則須搭配使用舊的 model,像是 dijit/tree/TreeStoreModel 或是 dijit/tree/ForestStoreModel。

在網頁下載 3 秒後,會在 "/" 下加入一個名為 "home" 的新物件節點,並會在畫面中顯示出新加入的節點。

CSS

<style>
html {
    width: 100%;
    height: 100%;
}
body {
    margin: 0 auto;
    width: 1000px;
    height: 100%;
    padding-top: 20px;
}
</style>

CSS 中沒有特別的樣式需要設定。

HTML

<body class="claro">
    
</body>

HTML 中只要設定一個掛載點。

Script


第 24~33 行定義 store 中的資料,每個子物件具有一個 parent 屬性,指出哪個物件為其父物件,這種格式稱為關聯式 (relational),只有一層的資料結構。如果 Tree 中的資料需要動態改變時,只能使用這種格式。
第 36~42 行建立一個 store,並實作 getChildren() 函式。
第 45 行用一個 dojo/store/Observable 將 store 包覆,讓它能監控資料變更,並通知 dijit/Tree。
第 48~58 行建立 dijit/tree/ObjectStoreModel,並實作 mayHaveChildren() 函式,若有任何物件的 parent 屬性值等於傳入物件的 id 屬性值,即表示該物件為傳入物件的子物件。有子物件時,query 後的結果其 length 會大於 0。
第 61~72 行建立 dijit/Tree,並呼叫 startup() 函式,將其在畫面上呈現。
showRoot:true 設定要顯示根節點,true 為預設值。設定為 false 時,會隱藏根節點。
第 75~77 行設定在下載網頁 3 秒後,在 store 中加入一個 id 為 "home" 的物件,物件加入後,dijit/Tree 會在畫面上顯示新物件的加入。注意這裡是使用 observableStore 而不是 treeStore。

2015年11月4日 星期三

dijit/layout/TabContainer

dijit/layout/TabContainer

簡介

dijit/layout/TabContainer 也許是除了 dijit/layout/BorderContainer 之外,另一種廣泛被使用的網頁佈局元件了。外觀的變化也多,標箋可以依設計放在內容的上、下、左,右四個方向的其中一個。若標箋過多,畫面上容納不下,還會自動產生可以移動標箋的按鈕,或依設定產生一個下拉式的選單,直接選取所要查看的內容。

範例

下圖是寬度足以容納所有標箋時的樣子。在網頁下載 3 秒後,會選定顯示 Tab_3 的內容;6 秒後,會在「主控台」列示當時展示內容的 dijit。

下圖是寬度不足以容納所有標箋時,自動產生向左、向右箭頭的樣子。

下圖是寬度不足以容納所有標箋時,自動產生向左、向右箭頭,同時設定 useMenu:true,額外產生下拉式選單的樣子。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body{
    width: 1000px;
    height:100%;
    margin:0 auto;
    padding-top:20px;
}
</style>

CCS 中沒有特別的設定。

HTML

<body class="claro">
    
</body>

HTML 裡只要設定一個掛載點既可。

Script


第 19~25 行建立一個 TabContainer 做為容器。
doLayout:true 設定固定容器的大小,不隨展示內容的多寡而變更容器的大小。
tabPosition 設定標箋所在的位置,有 top, bottom, left-h 及 right-h 四個值可以使用。
useMenu:true 設定會在標箋過多時,額外生成一個下拉式的選單。

第 26~54 行依序建立 5 個 ContentPane 並加入 TabContainer 之中,第一個 Tab 設定為可以關閉,此時在標箋的標示右方會出現一個 X 的符號,按下此符號,會移除這個標箋及其內容。

第 58~60 行建立一個定時器,,在網頁下載 3 秒後,用程式選擇顯示 Tab_3 的內容。
第 61~63 行建立另一個定時器,,在網頁下載 6 秒後,在「主控台」列示當時顯示內容之標箋的 dijit 元件。

dijit/layout/StackContainer

dijit/layout/StackContainer

簡介

dijit/layout/StackContainer 是 dojo 中對網頁內容的一種佈局方式。取名叫 "Stack",就知道內容是像堆疊一般堆在一起,在上方有個控制器,控制器中有對應各份內容的按鈕,點按按鈕,即會顯示對應的內容。

範例

範例中用程式法建立了一個 StackContainer 以及 StackController 做為控制器。另外在控制器的前後端各加了一個按鈕,讓展示的內容可以向前,或向後以輪轉的方式顯示內容。在範例中使用了 dojox/layout/ContentPane 做為內容的容器,因此所有在 dojox/layout/ContentPane 可以設定的參數或可使用的函式,都可以被設定和使用。網頁下載 3 秒後,會在「主控台」中列示當時顯示內容頁的 dijit 物件。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body{
    width: 1000px;
    height:100%;
    margin:0 auto;
    padding-top:20px;
}
.box {
    width:400px;
    height:300px;
}
.left {
    float:left;
}
.right {
    float:right;
}
</style>

.box 定義了整個 StackController 加上 StackContainer 的尺寸。如果控制器的寬度過大,版面就會亂掉,所以要當握控制器寬度及整個元件寬度的配合。
.left 和 .right 定義了將向前按鈕和向後按鈕置放於控制器的左右兩端。

HTML

<body class="claro">
    
</body>

HTML 中,定義了各個元件的掛載點。將兩個按鈕放在 <span> 的標記中,藉著控制 <span> 標記的位置來控制按鈕的位置。

Script


第 22~25 行建立了一個 StackContainer 的容器。
doLayout:true 固定了 StackContainer 容器的大小。如果設定為 false 時,容器會隨著顯示內容的的大小而改變。
第 27~40 行依序建立了三個 ContentPane 並加入 StackContainer 之中。
title 設定控制器中按鈕的標示。
第 42~45 行建立 stackController。
containerId 屬性值指定表控制的 StackContainer 名稱。
第 46~58 建立兩個按鈕,一個用 back() 函式來控制向前輪轉,一個用 forward() 函式來控制向後輪轉。
第 63~66 行建立個定時器,於網頁下載後 3 秒在「主控台」中列示當時顯示內容頁的 dijit 物件。
selectedChildWidget 屬性可以取得目前顯示內容之 ContentPane 的 dijit。

2015年11月3日 星期二

dijit/layout/AccordionContainer

dijit/layout/AccordionContainer

簡介

dijit/layout/AccordionContainer 是 dojo 的一種佈局方式,顧名思義,它就像一個手風琴 (accordion),透過點按抬頭欄 (title bar) 以顯示內容。

範例

範例中用程式法建立了一個 AccordionContainer。也在每個抬頭欄的前方加上了表示展開和收歛的小箭頭。在範例中使用了 dojox/layout/ContentPane 做為內容的容器,因此所有在 dojox/layout/ContentPane 可以設定的參數或可使用的函式,都可以被設定和使用。網頁下載 3 秒後,會在「主控台」中列示當時顯示內容頁的 dijit 物件。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body{
    width: 1000px;
    height:100%;
    margin:0 auto;
    padding-top:20px;
}
.claro  .dijitAccordionArrow {
    background:url("js/libs/dijit/themes/claro/images/spriteArrows.png") no-repeat -14px top;
    width:7px;
    height:8px;
    margin-top:-1px;
}
.claro  .dijitAccordionTitleSelected .dijitAccordionArrow {
    background:url("js/libs/dijit/themes/claro/images/spriteArrows.png") no-repeat;
    margin-top:-1px;
}
</style>

.claro .dijitAccordionArrow 設定了表示內容收歛時用的小箭頭圖像,收歛時的箭頭朝右。
.claro dijitAccordionTitleSelected . dijitAccordionArrow 設定了內容展開時的小箭頭圖像,展開時箭頭朝下。
要特別注意圖像所在內容的路徑,必須依照檔案的目錄結構,修改 url 路徑的值。

HTML

<body class="claro">
    
</body>

HTML 中只需設定一個掛載點。

Script


第 19~22 行建立了一個 AccordionContainer 的容器。
doLayout:true 固定了 AccordionContainer 容器的大小。如果設定為 false 時,容器會隨著顯示內容的的大小而改變。
第 23~36 行依序建立了三個 ContentPane 並加入 AccordionContainer 之中。
title 設定抬頭欄的內容。
content 設定所要顯示的內容,內容可以是 HTML 碼。
因為是使用 dojox/layout/ContentPane,所以也可以用 href 這個屬性來動態載入內容。
selected:true 可以用來指定在顯示 AccordionContainer 時,預設要顯示那一份內容。
selectedChildWidget 屬性可以取得目前顯示內容之 ContentPane 的 dijit。
第 39~42 行設定一個定時器,於網頁下載後 3 秒在「主控台」中列示當時顯示內容頁的 dijit 物件。

2015年11月1日 星期日

dojo/topic

dojo/topic

簡介

dojo/topic 是另一個和 dojo/on 一樣可以藉由某事的發生,而針對某事採取對應行動的機制。不同的地方在於:dojo/on 比較偏向單一的事件,單一的對應行動;dojo/topic 則偏向於藉由發佈單一的主題訊息 (topic),而相對會有至少有一個及一個以上的對應行動。

topic 有二個常用的函式:

publish(message, obj):
用來發佈一項主題訊息,第一個參數是所要發佈的主題訊息,為字串型態,字串的內容自定。第二個是隨發佈主題訊息所傳遞的相關資料,為物件型態,物件的內容自定。
var handle = subscribe(message, action):
用來訂閱主題訊息。第一個參數是所要訂閱的主題訊息,為字串型態,字串的內容須和發佈的主題訊息內容相同。第二個參數則是收到訊息後所要採取的對應行動,型態為函式,函式的參數為 publish() 函式所傳遞的物件。傳回的變數 handle,具有 remove() 函式,用 handle.remove() 可以取消對主題訊息的訂閱。

範例

範例中建立了七個灰色方塊,點按方塊時,該方塊會訂閱主題訊息,程式每三秒會發佈一次主題訊息,有訂閱主題訊息的方塊則會在接到主題訊息時,改變其背景顏色。範例中不能取消主題訊息的訂閱。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body {
    margin: 0 auto;
    width:1000px;
    height:100%;
    padding-top:20px;
}
.box {
    box-sizing:box-sizing;
    margin:10px;
    width:60px;
    height:60px;
    border:3px solid gray;
    background-color:#EEEEEE;
    float:left;
}
.box:hover {
    cursor:pointer;
}
</style>

CSS 中 .box 定義方塊的樣式, .box:hover 定義當游標移到方塊上方時,改變游標的樣式。

HTML

<body class="claro">
    
</body>

HTML 中,定義七個方塊,在點按方塊時,會呼叫 app.subscribe() 函式訂閱主題訊息。

Script


第 22 行定義一個含有彩虹七種顏色的字串陣列。
第 25~27 行則是各方塊訂閱主題訊息及所採取之行動的函式。訂閱的主題為 "changeColor"。
第 30~32 行定義每隔 3 秒鐘,,發佈一次 "changeColor" 主題訊息,發佈主題訊息時,並沒有相關的資料要傳遞,所以第二個參數為一個 null 指標。

2015年10月31日 星期六

dojo/on (double click)

dojo/on (double click)

簡介

當一個圖形介面元件需要同時用到點按 (click) 及 雙點按(double click) 時,常常會碰到一件很惱人的事;也就是每次雙點按時,都會產生三次事件,二次點按,然後一次雙點按。這是因為每次點按之間的逾時值 (timeout) 太短;所以有人建議同一個圖形介面元件上不要同時實作點按和雙點。或者,透過延長點按與點按之間的逾時值來解決這個問題。同一個圖形介面元件上,是可以同時實作點按和雙點按的。

範例

範例中建立一個灰色方塊,同時在方塊上實作點按及雙點按兩種功能。每次點按或雙點按時,都會出現視窗顯示點按的型態。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body {
    margin: 0 auto;
    width:1000px;
    height:100%;
    padding-top:20px;
}
.box {
    box-sizing:box-sizing;
    width:200px;
    height:200px;
    border:3px solid gray;
    background-color: #EEEEEE;
}
.box:hover {
    cursor:pointer;
}
</style>

CSS 中.box 定義方塊的樣式,在游標移到方塊上方時,改變游標的樣式。

HTML

<body class="claro">
    
</body>

HTML 中只需定義一個方塊的掛載點。

Script


第 20~22 行建立點按 (click) 事件的監聽和處理。
第 23~25 行建立雙點按 (double click) 事件的監聽和處理。
第 27 行的 clickDelay 是點按和點按之間的逾時值,也就是說,在這個時間內,如個碰到兩個點按,則視為雙點按; 如果二個點按之間的間隔時間,長於 clickDelay 的值,則視為兩次的點按。
第 28 行設定一個 clickTimer 變數,在逾時值滿足後,呼叫處理函式。
第 29~38 行為點按的處理函式。
第 39~47 行為雙點按的處理函式。

2015年10月30日 星期五

dojo/on

dojo/on

簡介

dojo/on 是 dojo 中用來連接事件 (event) 和事件監聽器 (event listener) 的模組。用法並不難,其中有幾個常用的函式,列示語法如下:

on(target, type, listener)
當 target 觸發 type 事件時,執行 listener 監聽函式。傳回一個 handler 物件。
on.once(target, type, listener)
當 target 觸發 type 事件時,執行 listener 監聽函式。但只有第一次觸發時,會執行監聽函式,隨後觸發的事件都即不再執行監聽函式。傳回一個 handler 物件。
on(target, type, listener)
在 target 元件觸發 type 事件時,執行 listener 函式,傳回值為事件的 handler。
on.emit(target, type, eventParam)
促使 target 觸發一個 type 型態的事件。eventParam 是一個 Javascript 的物件,內中包含所要傳給監聽函式的參數。傳回一個 handler 物件。
handler.remove()
移除監聽器。handler 為上面各函式所傳回的物件。

on.once() 和 on() 的用法完全一樣,唯一不同的地方是 on.once() 只會觸發一次事件,之後會自動移除事件的 handler,之後就不會再觸發相同型態的事件了。
on.emit() 函式執行時會引起 target 觸發 type 的事件,第三個參數 eventParam 是一個物件,物件中可以定義事件的屬性,這些屬性會被融入 (mixin) 觸發的事件物件中,可以藉此傳遞參數給事件監聽器。由 on.emit() 所觸發的事件物件是 Event,和由圖形介面元件所觸發的 MouseEvent 不太一樣,最大的差異在兩者具備屬性的個數。

範例

在範例中建立了兩個方塊圖形元件,點按左邊的淡紫色方塊會在主控台中,將事件物件印出來,按幾次印幾個。只要一按右邊的淡綠色方塊,就會讓淡紫色的方塊再觸發一次事件,隨後移除事件的 handler,之後再按淡紫色的方塊,就再也不會觸發任何事件了。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body {
    margin: 0 auto;
    width:1000px;
    height:100%;
    padding-top:20px;
}
.box {
    box-sizing:border-sizing;
    margin:10px;
    width:200px;
    height:200px;
    border:3px solid gray;
    background-color: #EEEEEE;
}
.box:hover {
    cursor:pointer;
}
.violet {
    background-color:#EE82EE;
    float: left;
}
.lightGreen{
    background-color:#98FB98;
    float:left;
}
</style>

CSS 中,.box 定義了兩個方塊元件的共通樣式,.box:hover 定義了游標在移動到方塊上方時,改變游標的樣式。.violet 及 .lightGreen 則定義各自的背景顏色及位置。

HTML

<body class="claro"<
    
</body>

HTML 中就定義兩個 <div< 用來顯示兩個方塊。

Script


第 21~23 行把由淡紫色方塊觸發的事件和處理函式串起來。
第 25~27 行是事件處理函式,單純只是把事件物件在主控台印出來。
第 30~33 行把由淡綠色方塊觸發的事件和處理函式串起來。在處理函式中,再讓淡紫色方塊觸發一次 click 事件。這事件只會觸發一次。
第 35 行把淡紫色方塊的事件處理器移除。

dojo Events

dojo Events

簡介

為了能應付各種不同的流覽器對事件物件(event object) 有不同的定義及不同的處理方式,dojo 對事件物件的定義及處理方式做了正規化 (normalized),確保在 dojo 中處理事件時,事件物件的屬性或處理方法不會因為流覽器不同,而有所不同。在 dojo 中,事件物件大致分為兩種: Event 及 MouseEvent。Event 物件由程式觸發,傳回物件的屬性較少,觸發型別 (type) 可以自定;自訂型別時,中、英文皆可使用,唯使用英文時,所有大寫字母 (Uppercase) 均會被轉換成小寫 (Lowercase);因此,自定型別時最好全部使用小寫字母,"_" 及 "-" 兩個符號也可以使用。所有的 MouseEvent 均由使用者經由圖形介面元件所觸發,觸發的型別有固定種類,傳回物件的屬性比 Event 物件多,多出來的屬性大多是具有游標相關的資訊。至於事件物件的屬性及可能的型別,可說是族繁不及備載;在 w3cschools 網頁中有詳細的列示及解釋。也可以在 JavaScript 中,當使用者觸發圖形介面元件的事件時,用 console.log(event); 指令,然後到主控台去查看完整的物件屬性。


dojo 正規化後常用之事件物件的屬性如下:

target:
觸發此事件的元素 (element)。
currentTarget:
目前的元素,指的是在事件上傳 (bubble up) 的階段,目前處理此事件的元素。
type:
觸發事件的型別。
layerX:
事件觸發時,相對於處理此事件的元素,游標所在的 X 軸座標。
layerY:
事件觸發時,相對於處理此事件的元素,游標所在的 Y 軸座標。
pageX
事件觸發時,相對於流覽器視窗,游標所在的 X 軸座標。
pageY
事件觸發時,相對於流覽器視窗,游標所在的 Y 軸座標。
relatedTarget:
在觸發 mouseover 及 mouseout 事件時,游標所在,或離開的元素。
charCode:
觸發按鍵事件時,按鍵的字母鍵值。
keyCode:
觸發按鍵時,按鍵的鍵盤碼(當觸發事件的按鍵並非一般字母鍵,例 Enter, esc 鍵)。

另有常用到的函式如下:

event.preventDefault():
停止事件預設設處理動作。
event.stopPropagation():
停止事件的上傳 (bubble up) 動作。
event.stopImmediatePropagation():
停止事件的上傳動作,同時停止觸發此元素的其它事件處理器 (handler)。
event.stop(event):
停止事件預設的處理動作,同時停止事件的上傳動作。

dojo 用來連接事件 (event) 及事件處理器 (event handler) 的模組元件為 dojo/on。繼承 dojo/evented 類別的物件則具有 on() 及 emit() 兩個函式。

2015年10月28日 星期三

dojo Creating Template Widget

dojo Creating Template Widget

簡介

dojo 除了提供一系列豐富的圖形介面的元件,也允許程師設計師自行建構圖形介面元件以符合應用的特殊需求。dijit/_WidgetBase 是所有圖形介面元件的基礎,所有的圖形介面元件都繼承自 dijit/_WidgetBase。要能夠在 dojo 中自行開發圖形介面元件,深入瞭解 dijit/_WidgetBase 是絕對必須的。

首先,dijit/_WidgetBase 預先定義了一些每個圖形介面元件都會繼承的共同屬性:

id:
用來辨識圖形介面元件的唯一名稱,型態為字串。可以自行指定或由 dijit 自行產生。
lang:
指定取代 dojo 預設使用的語言,這個屬性很少用到。
dir:
如果指定語言是從右至左,就用這個屬性來指定。
domNode:
圖形介面主要的 DOM 元素(Element),多數的圖形介面元件都會修改 HTML 的結構,這個屬性可以參考到組成圖形介面最終的 HTML 元素及節點。
class:
圖形介面元件 domNode 之 HTML 的 class 屬性。
style:
圖形介面元件 domNode 之 HTML 的 style 屬性。
title:
圖形介面元件 domNode 之 HTML 的 title 屬性。
baseClass:
圖形介面元件在 CSS 中的基本 class 屬性。
srcNodeRef:
圖形介面元件在 DOM 中的原始掛載點,某些圖形介面在建構時,這個掛載點會被重設或清除。

另外,dijit/_WidgetBase 定義了數個函式,藉以掌控整個圖形介面元件的生命週期,各函式名稱依執行先後次序列示如下:

  • constructor() // common to all prototypes, called when instantiated
  • postScript()
    • postMixInProperties()
    • buildRendering()
    • postCreate()
  • startup()

以下介紹各函式的作用:

constructor()
是所有類別都具備的函式,在實體化物件時,會被呼叫一次。
postScript()
會先呼叫 create() 函式,在 create() 函式中又會依次呼叫 postMixInProperties(), buildRendering(), 及 postCreate() 三個函式。
postMixInPorperties()
作用在將建立元件時所傳入的屬性參數或函式融入 (mixin) 到既有的屬性及函式中。
buildRendering()
作用在建構所有介面的 HTML 元素,並設定 domNode 的值,這個函式執行完畢時,圖形介面的 HTML 元素都己建構並設定完畢,但尚未將這些元素加入到 HTML 主文件中。
postCreate()
這個算是最重要的函式了,在所有的屬性都定義完畢,而且圖形介面相關的 HTML 段落都己建置完成,且加入 HTML 主文件之後,(將 HTML 段落加到 HTML 主文件的動作,在呼叫完 buildRendering() 和呼叫 postCreate() 兩函式之間完成),才會執行這個函式。但要注意的是,如果此元件有子元件時,子元件在此刻未必己經加到主元件中,因此,在此階段還不能進行元件最終尺寸的計算。
startup()
是第二重要的函式了,在圖形介面相關的 HTML 段落加入主文件後,同時所有的子圖形介面都己完成之後,這個函式才會執行。用程式法建立圖形介面元件時,最好在建立完畢後呼叫 startup() 函式,以確保所有的動作都完成。

另一個非常重要的工具是 dijit/_TamplatedMixin。有些複雜的圖形介面元件,其 HTML 段落非常的複雜,如果要靠 API 一步一步組成最終的 HTML 碼,實在是曠日費時,而且容易出錯。如果能直接寫成最終的 HTML 碼,直接掛載到預定的位置,那就容易多了。而 dijit/_TemplatedMixin 就職司此項工作;它可以讀取一個含有 HTML 段落的檔案,將其內容處理後掛載到 HTML 主文件上的指定掛載點,更進一步的還提供了參數取代的功能,可直接將屬性的定義以參數取代的方式代入 HTML 碼中。

在 HTML 的模版 (template) 中置入 ${propName} 字串,dijit/_TemplatedMixin 便會用名為 propName 的屬性值,來取代這個字串。

在模版中,還可以定義兩個屬性:

data-dojo-attach-point="nameNode"
會在 widget 中建立一個名為 nameNode 的屬性,其值可以直接參考到這個 DOM 元素。
data-dojoattach-event="onClick:handler"
用在將這個 DOM 元素連接到觸發的事件 (click),並呼叫事件的處理函式 handler()。

除此之外,dijit/_TemplaedMixin 還會為 widget 預設建立兩個屬性值:

domNode:
這個屬性值可以直接參考到 widget 中最主要的 DOM 元素。
containerNode:
如果這個 widget 有包含其它的子圖形介面元件,用這個屬性可以直接參考到子元件的 DOM 元素。

如果在 HTML 的模板 (template)中又包含了其它的 dijit,此時,必須另外 require 另一個名為 "dijit/_WidgetsInTemplateMixin" 的模組,同時,用到的 dijit 模組也必須 require 進來。 當使用用外部定義的 HTML 檔案時,要藉著 dojo/text 這個插件 (plug-in) 將檔案內容讀進來。

範例

範例中,自定一個圖形介面元件,元件的作用是計數器,每點一下元件,其中的數字便會加 1。這個範例設計的並不是很完善,主要的作用是在解釋如何建立一個自定的圖形介面而己。例如:如果不改變元件的大小,元件只能容納 2 位數。如果改變元件的大小,字形不會跟著變化,位置也不會保持在中間等等。

CSS

<style>
html{
     width:100%;
     height:100%;
}
body {
     margin:0 auto;
     width:1000px;
     height:100%;
     padding-top: 20px;
}
</style>

屬性都在 widget 中定義了,所以 CSS 中沒有什麼要寫的。

HTML

<body class="claro">

My Counter

</body>

HTML 中要設定一個掛載點,注意 data-dojo-type 屬性的值。

HTML

首先,先根據圖形介面所要求的外觀,建一個新檔,由網頁所在位置起始,檔案的相對路徑位置名為 "js/app/widgets/templates/MyCounter.html"。因為用 SyntaxHighlighter 在處理 ${baseClass} 時會變成 ${baseClass}="",所以這一段程式碼不用 SyntaxHighLighter 處理。內容如下:


<div ${baseClass}
    data-dojo-attach-point="buttonNode"
    data-dojo-attach-event="onClick:_increment">
    <div
        data-dojo-attach-point="counterNode"
        style="padding:10px 0px; font-size:48px; text-align:center}"></div>
</div>

在模版中,定義了兩個 data-dojo-attach-point,一個名為 "buttonNode",另一個名為 "counterNode",這樣在程式中比較好操作。此外,定義了一個 data-attach-event,在元件觸發點按事件時,呼叫 _increment() 處理函式。另有一個屬性變數 ${baseClass} ,但程式中並沒有針對 baseClass 屬性定值,所以並不會在最終的 HTML 裡,產生任何 class="someClasses" 的設定。


其次,建立一個新檔,由網頁所在位置起始,檔案的相對路徑為 "js/app/widgets/MyCounter.js"。

define([
    "dojo/_base/declare",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dojo/text!./templates/MyCounter.html",
    "dojo/dom-style"
    ],
function(
    declare,
    _WidgetBase,
    _TemplatedMixin,
    template,
    style
){
    return declare("MyCounter", [_WidgetBase, _TemplatedMixin], {
        // counter
        value: 0,
        baseClass:"",
        width:"64px",
        height:"64px",
        backgroundColor:"yellow",
        border:"10px solid blue",
        borderRadius:"10px",
        templateString:template,
        constructor: function(){
            this.inherited(arguments);
        },
        postscript:function(){
            this.inherited(arguments);
        },
        // minin with the parameters passed in
        postMixInProperties:function(){
            this.inherited(arguments);
        },    
        // create the DOM for this widget
        buildRendering: function(){
            this.inherited(arguments);
        },
        // setup the style of DOM node      
        postCreate: function(){
            var bNode = this.buttonNode;
            style.set(bNode, "width", this.width);
            style.set(bNode, "height", this.height);
            style.set(bNode, "background-color", this.backgroundColor);
            style.set(bNode, "border", this.border);
            style.set(bNode, "border-radius", this.borderRadius);
            style.set(bNode, "text-align","center"); 
            var cNode = this.counterNode;
            cNode.innerHTML = 0;
            this.inherited(arguments);
        },
        startup:function(){
         this.inherited(arguments);
        },
        // every time the user clicks the button, increment the counter
        _increment: function(){
            this.counterNode.innerHTML = ++this.value;
        },
        _getValuerAttr:function(){
            return this.value;
        },
        _setValueAttr:function(number){
            this.value = number;
            this.counterNode.innerHTML = this.value;
        }
    });
});

第 5 行用 dojo/text 從相對路徑為名為 "./templates/MyCounter.html" 檔案中讀入 HTML 段落的內容。 放在 template 變數中,然後在第 24 行將其設定成 templateString 屬性的值。
第 17~24 行設定各屬性值。
第 41~49 行設定 domNode 的各項外觀的屬性。
第 56~58 行定義事件處理器。
第 59~65 行定義兩個供外部使用的函式,一個用來讀取屬性 value 的值,有就是計數器的值,另一個用來設定。要注意的是這兩個函式的命名方式,都是 _get${PropName}Attr() 及 _set${PropName}Attr(),其中 ${PropName} 字串,用屬性的名稱來取代。

最後,則是主網頁中的內容。


建立好自定的 widget 之後,用法就和 dijit 中的圖形介面元件的用法一樣,唯一要注意的是元件的路徑名,必須正確。
第 18~25 行在主控台中印出各個和 DOM node 有關之屬性的值,記得到主控台去檢查印出值,必詳細思考一下。建立 widget 的步驟還算複雜,最好多多修改範例程式,並檢查結果,以充分瞭解其中的細節。

2015年10月24日 星期六

dojo AMD

dojo AMD

簡介

將應用程式模組化,這個觀念在軟體業界己經行之有年。程式經過詳細規劃並模組化後,比較容易撰寫、管理及維護。在 dojo 中,一個模組 (module) 在系統中就是一個檔案,每當使用 require() 要求載入一個模組時,載入器 (loader) 便會在檔案系統中尋找符合名稱的模組檔案,將其載入到 Javascript 的執行環境中,程式便會獲得一個參考值;並透過這個參考值讀取模組中的屬性值,或呼叫模組中的函式。只要知道在 dojo 中如何建立一個類別 (Class)之後,建立一個模組並非難事。

建立一個模組時,最重要的就是 define() 函式。其語法如下:

define(
  moduleId,
  // (optional; string)
  // an explicit module identifier naming the module being defined      
  dependencies,  
  // (optional; array of strings) 
  // list of module identifiers to load before calling factory
  factory 
  // (function or value) 
  // the value of the module, or a function that returns the value of the  
  // module
)
    moduleId
    指定模組的名稱,這個參數是選項,一般都不賦予值;從缺時,載入器 (loader) 便使用檔案名稱做為模組的名稱。模組若是用在定義一個類別時,檔案名稱開頭的第一個字母都會大寫,以符合物件導向程式語言的命名慣例,若是傳回一個物件,則檔案名稱的第一個字母則保持小寫。
    dependencies
    也是選項,不賦予值時,表示該模組完全獨立存在,與其它模組不相關。若模組的建立需依賴其它模組,也就是會使用到其它的模組時,要將所有相依的模組名稱放在陣列裡傳入。
    factory
    其實就是個函式;用來建立一個類別 (class) 或是物件 (object) 的函式,在物件導向的程式語言中有個特殊的名字,叫 factory。這個函式裡,便撰寫建立一個類別或物件的程式,這個函式一定要傳回一個參考值,否則其它模組或程式就沒有辦法使用這個模組了。

建立模組時,要先在檔案系統裡依照模組的分類及彼此間的關係建立目錄結構,以便將來載入及維護。

/* content in file js/app/Person.js */
define([
    "dojo/_base/declare"
    ],
function(
    declare
){
    var Person = declare(null, {
        constructor: function(name, age, residence){
            this.name = name;
            this.age = age;
            this.residence = residence;
            Person.count++;
        }
    });
    Person.count = 0;    // class variable
    return Person;
});

在 js/app/Person.js 這個檔案中,撰寫了一個名為 Person 的類別,因為要給予一個類別變數,所以先將類別指派給一個變數,定義完類別變數後,才將變數傳出去。這裡正好變數的名稱也取名為 Person,其實取什麼名字都可以。

第一個參數從缺,所以會用檔案的名稱做為模組的名稱。因為函式中用到了 dojo 的 declare() 函式,也就是這個模組和 "dojo/_base/declare" 這個模組有相依性,因此要相依模組的陣列中列出這個模組的名稱。隨後就是宣告類別,並傳回類別的參考值。

/* content in file js/app/Employee.js */
define([
    "dojo/_base/declare",
    "app/Person"
    ],
function(
    declare,
    Person
){
    return declare(Person, {
        constructor: function(name, age, residence, salary){
            this.salary = salary;
        },
        askForRaise:function(){
            return this.salary * 0.02;
        }
    });
});

在 js/app/Employee.js 中,則建立名為 Employee 的類別,因為 Employee 繼承了 Person,所以在相依模組的陣列中,也將 Person 模組列入。

/* content in file js/app/Boss.js */
define([
    "dojo/_base/declare",
    "app/Employee"
    ],
function(
    declare,
    Employee
){
    return declare(Employee, {
        askForRaise:function(){
            return this.inherited(arguments) * 2; // calling parent's method, also modify the method
        }
    });
});

在 js/app/Boss.js 中則建立名為 Boss 的類別,因為 Boss 繼承了 Employee,所以在相依模組的陣列中,也列入 Employee。雖然 Employee 和 Person 也有相依,但在此處無需列入 Person,載入器在載入 Employee 模組時,會自行依照 Employee 類別相依陣列的內容,加載 Person 模組。

在使用這些自定的模組時,要記得在 dojoConfig 中定義模組在檔案系統中放置的位置。




只要定義好自定模組在系統中的位置,在使用這些模組時,就和使用 dojo 的模組沒有什麼兩樣了。

dojo Creating Classes

dojo Creating Classes

簡介

雖說在 Javascript 用的是 prototyping 的繼承模式,並沒有其它物件導向程式語言中所謂「類別」(Class)的概念,在 Javascript 中只有「物件」(Object) 的存在,而且物件可以繼承另一個物件。但 dojo 在 Javascript 的基礎上還是實作了類似「類別」的概念。dojo/_base/declare 這個模組就是 dojo 中用來宣告一個類別的函式。在 dojo 中,物件可以多重繼承 (Multiple Inheritance)。在實務上,宣告類別時,多半會寫成模組,以單獨的檔案形式存在,但此篇只先討論在 dojo 中類別的宣告方式。

declare 的語法如下:

declare(classId, superClasses, mixin)

declare() 函式有三個參數,分別說明如下:

    classId
    為選項,可以不給,不給時該類別稱為「匿名類別」(Anonymous Class)。給予時,需給予包含命名空間(namesapce) 的類別名,整個名稱會是一個全域變數,格式為 "namespace/ClassId"。配合物件導向程式語言的一般命名規則,類別名稱的第一個字母會大寫。
    superClasses
    賦予值可以是 null 、一個類別名或是一個類別名陣列。賦予值為 null 時,表示此類別沒有任何要繼承的其它類別。賦於值為單一類別名時,表示此類別僅有一個父類別需要繼承。賦予值為一類別名陣列時,表示多重繼承,此類別會繼承陣列中所有的類別。此時要特別注意陣列中類別名在陣列中的前後次序,陣列中的第一個類別稱為基礎類別 (base class),由此類別依序將後繼類別的屬性和函式融入 (mixin),意味著當前類別和後繼類別具有相同屬性名或函式名時,後繼的屬性值和函式會取代先前類別的屬性值或函式。
    mixin
    最終的參數則是一個物件,此物件具有該物件特有的屬性及函式。同樣的,若繼承類別中的屬性名或函式名與此參數所提供的屬性名或函式相同時,則此參數中的屬性值和函式會取代繼承類別中的屬性值和函式。

mixin 中有個很特殊的函式叫 constructor(),這個函式就是物件的建構子。在每次用 new 這個操作子以建構一個新物件時,這個函式都會被呼叫一次。因此,這個函式通常都會將傳遞進來的參數,用來初始化 (initialize) 建構的物件。同時,這個函式會先行呼叫父類別的 constructor() 函式,並傳入參數,以初始化父類別的屬性;之後,再初始化本身的屬性。

另一個很特殊的函式是 this.inherited(arguments),用來呼叫父類別中的函式。語法如下:

inherited(methodId, arguments, [arg1, arg2,...]);
    methodId
    指定要呼叫父類別函式的名稱,如果從缺,則呼叫父類別中與呼叫 inherited() 函式相同名稱的函式,如果呼叫 inherited() 的函式沒有明確的函式名稱,例如「匿名函式」時,則須明確指定 methodId 的值。
    arguments
    Javascript 中的保留字,是一個含有全部傳入參數的陣列。
    [arg1, arg2,...]
    以此陣列成為呼叫父類別函式時的參數。從缺時,則傳入 arguments。


declare("Person",null, {
    name = "John"
});

var Person = declare(null, {
    name = "John"
});

以上兩種寫法都會產生一個名為 Person 的類別。

Script


第 9~15 行建構一個名為 "Person" 的類別。
第 17 行則建立一個類別變數 (class variable),計算由此類別所建構的物件數。
第 19~25 行建構一個名為 "Employee" 繼承 "Person" 的類別,加入 salary 屬性。
第 28~32 行建構一個名為 "Boss" 繼承 "Employee" 的類別,並修改 askForRaise() 函式,在函式中呼叫 "Employee" 的 askForRaise() 函式,取得傳回值後,再乘 2 。

2015年10月20日 星期二

dijit/form/HoriztonalSlider

dijit/form/HoriztonalSlider

簡介

dojo 的 Slider (滑動條)有二個:dijit/form/HorizontalSlider 及 dijit/form/VerticalSlider。看名字就可以知道,一個「橫躺」,一個「直立」,功能和操作方式都相同,透過滑動指示游標來決定輸入值,用方向鍵來移動指示游標也行。slider 的建立比多數的 dijit 要複雜,滑動條和刻度和數值標示,分成了三個元件,建起來頗為費時。

範例

在範例中先建立了一個 form manager 做為容器,內中建立了二個 slider,一個用宣告法,一個用程式法;另外建立了一個按鈕來讀取輸入值。記得打開「開發者工具」的「主控台」查看結果。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body {
    margin: 0 auto;
    width:1000px;
    height:100%;
    padding-top:20px;
}
</style>

這次直接在元件中定義樣式。

HTML

<body class="claro">
    
Declarative
  • 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Programmatic
  • 0%
  • 10%
  • 20%
  • 30%
  • 40%
  • 50%
  • 60%
  • 70%
  • 80%
  • 90%
  • 100%
</body>

第 5~27 行用宣告法建立一個 Slider。
第 12~13 行建立刻度。
第 14~25 行建立數值落點標示
第 32~47 行建立程式法的掛載點,掛載點共有三個,各在第 32 行、第 33 行及第 46 行,數值落點標示則以 <ul> 標記宣告。

Script


第 24~37 行用程式法建立 slider 的滑動條。各參數作用如下:
name 為輸入值的變數名稱。
style 設定樣式。
value 設定預設值。
minimum 及 maximum 設定最小值及最大值。
discreteValues 設定最小值和最大值中間存在數值的節點個數。
showButtons 設定在滑動條的兩端是否要有按鈕,這兩個按鈕可以用來增加或降低輸入值,每次改變一個節點的值。
clickSelect 設定是否可以直接點選滑動條以輸入數值。
intermediateChange 設定是否在滑動指示游標移動的過程中,每次經過一個數值節點時,都要觸發一次 onChange 事件,預設值為 false,只在滑動指示游標停止時,觸發一次 onChange 事件。
onChange 設定在 onChange 事件發生時,要執行的函式。

第 39~42 行建立落點數值標示。
container 設定為 "topDecoration" 表示數值落點標示處於滑動條的上方。設定為 "bottomDecoration" 時則處於滑動條的下方,如宣告法的 Slider。

第 44~48 行建立刻度標示。
container 設定為 "topDecoration" 表示刻度處於滑動條的上方。設定為 "bottomDecoration" 時則處於滑動條的下方,如宣告法的 Slider。

第 51 行將程式法建立的 slider 向 form manager 註冊納管。

第 52~55 行設定按鈕在觸動時所執行的函式。

Slider 還提供了 increment(event) 及 decrement(event) 兩個函式,可以透過程式去改變 Slider 的值,參數 event 一定要給,在實作時,一般是因為某個事件被觸發了,才會去改變 slider 的值,把觸發的事件當成參數來傳就可以了。當用鍵盤改變 slider 的值時,就會呼叫到這兩個函式。

2015年10月19日 星期一

dijit/Editor

dijit/Editor

簡介

dijit/Editor 是 dojo 提供的一個 rich-text editor,意思就是編輯器具備很多功能,可以編排格式,改變字體、字型等等,比起 HTML 中提供的 textarea 功能強大多了。dijit/Editor 具有一個工具列,工具列的內容可以根據實務需要,透過插件 (plugin) 的方式增減圖像按鈕。編輯後的文字內容以 HTML 的格式儲存。

所有的 extraPlugins 都放在 dijit/_editor/plugins 和 dojox/editor/plugins 兩個目錄下,可以直接到目錄去看看有多少插件可供運用。唯 dojox/editor/plugins 下的插件,有些有自已的樣式表,放在 dojox/editor/plugins/resources/css 目錄下,在使用這些有樣式表的插件時,要記得把插件的樣式表也納入網頁之中。
所有的插件元件名稱都是第一個字母大寫,但在設定 plugins 及 extraPlugins 的陣列時,用的都是所謂的 short name, 拼法和元件的名稱一致,唯所有的字母都是小寫。

dijit/Editor 實作時採用了 iframe 來容納這個編輯器,如此一來,可以避免編輯器的內容影響到網頁,但同時也造成了一些困擾。像是宣告時要用 <div> 標記,而不是 <textarea>;無法受到 form 或 form manager 的管轄,因此在讀取輸入值時,得另做處理等等。

範例

範例中用宣告法建立了一個 dijit/Editor 的編輯器,並稍為改變了一下工具列的內容,以展示如何用插件變更工具列。以及兩個按鈕,一個用來設定編輯器的起始內容,一個用來讀取編輯過後的內容。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body {
    margin:0 auto;
    width:1000px;
    height:100%;
    padding-top: 20px;
}
#myEditor {
    width:400px;
    min-height:200px;
}
</style>

用 #myEditor 定義編輯器的樣式,將寬度設為 400px 寛,另設定了 min-height 為 200px 高。dijit/Editor 似乎會佔據固定約 350px 高的畫面區域,只要高度的定義小於 350px 時,底框線就會失踪。當內容超過視窗大小時,會自行出現捲動軸。

HTML

<body class="claro">
    

</body>

第 2~7 行用宣告法定義一個 dijit/Editor。
lang:'zh-TW' 設定提示用的文字為正體字,預設是簡體,dijit/Editor 似乎不能正確的使用網頁所設定的語言。
name 設定要儲存編輯內容的變數名稱,但 form manager 無法主動讀取編輯後的內容,必須手動設定。
plugins 設定要顯示在工具列的圖像按鈕。
extraPlugins 則設定另一組可以顯示在工具列的圖像按鈕。
如果不設定 plugins ,則工具列會顯示預設的所有圖像按鈕,加上 extraPlugins 所設定的按鈕。若兩個都不設定,則工具列會顯示所有預設的圖像按鈕。

第 8~9 行,建立兩個 dijit/form/Button ,一個用來設定編輯的內容,一個用來讀取編輯後的內容。

Script


第 8~12 行載入所要用到的插件,因為這些額外的插件並非介面的 dijit,所以,既便是用宣告法, dojo 的剖析器也不會自行載入這些插件,因此要明確的用 require 去下載。
第 23~26 行是讀取編輯內容的函式。
第 27~30 行是設定預設編輯內容的函式。單純的輸入文字,dijit/Editor 並不一定會產生 <div> 的標記將整個內容包起來,編輯後的內容可能會和預測的內容的有很大的出入,實務上要多測試才行。

2015年10月14日 星期三

dijit/form/DateTextBox

dijit/form/DateTextBox

簡介

在應用程式裡,處理日期這㮔資料也是個很令人頭痛的問題,因為不同的國家對日期的格式有不同的要求,年月日的前後排列順序也大不相同,連中間的分隔號,也各有所好。 dojo 的日期一律採用 ISO 8601 的日期格式做為儲存的標準格式,如果遇到不同的要求,才去做日期格式的轉換。

dijit/form/DateTextBox 提供了一個簡便的日期輸入方式,使用者可以直接輸入日期,或由下拉式的月曆中挑選所要輸入的日期。月曆也會根據語言的設定以適當的文字顯示。

範例

範例中用宣告法建立了一個 dijit/form/DateTextBox 的輸入欄位,另外還建立了一個按鈕以讀取欄位的輸入值,並以 alert() 函式顯示在畫面上。由讀取值可以看出 ISO 8601 的標準日期格式。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body {
    margin: 0 auto;
    width:1000px;
    height:100%; 
    padding-top:20px;
}
.dijitInputField {
    font-family:courier;
}
</style>

用 .dijitInputField class 來定義 dijit/form/DateTextBox 的輸入及顯示字型,用 input 標記的定義沒有用,因為在最終的產生 dijit 的 HTML 裡,真正的 input 標記的 type="hidden",被隱藏了,這種情況在很多的 dijit 裡都會發生,所以當 CSS 的設定無效時,得進到「開發者工具」裡去看最終 HTML 的長相,才能知道真正要設定那個 class 的樣式才會產生效果。

HTML

<body class="claro">
    
    
    
</body>

第 3~16 行用宣告法定義一個 dijit/formDateTextBox。各屬性的定義如下:
required:true 表示此欄位為必須輸入的欄位。
autoWidth 設定如果為 true 時,欄位的寬度會自動設定與下拉式月曆同寬。
constraints 設定對欄位的限制條件:
datePattern 設定欄位輸入及顯示的格式。
min 設定日期的最小值。
max 設定日期的最大值,此處設定為輸入的當日。
formatLength 設定顯示時的格式為短式 (short) 或長式 (long),但此欄位設定為長式時,會和 datePattern 的設定互斥,以 datePattern 的設定為優先。
hasDownArrow 的設定若為 false 時,欄位右邊不會出現向下的小箭頭。但當游標進入欄位時,仍會出現月曆。
promptMessage 為輸入提示訊息。
missingMessage 為欄位未輸入時的警告訊息。
invalidMessage 為輸入資料格式不正確時的錯誤訊息。
toolgipPosition 值為一陣列,列出顯示訊息時,訊息出現所在位置的優先順序。

Script


第 18~21 行設定按鈕按下時所要呼叫的函式。

2015年10月12日 星期一

dojox/widget/Standby

dojox/widget/Standby

簡介

在 dojo 中使用宣告法建立 dijit 時,在 dojo 的剖析器剖析 HTML 時,介面元件會先以流覽器的預設樣式顯示,然後再以 dijit 的外觀呈現。在這個過程中,畫面上會有「閃動」的情況發生,造成使用者的經驗不佳。最好的方式是顯示一個下載中的訊息或動畫,將畫面遮住,等到 dijit 準備好了,才顯示在畫面上。dojo 的套件也提供了一個動畫元件 dojox/widget/Standby 來做這件事。每建立一個 Standy 元件,可以在畫面上顯示一個下載中的動畫,可以透過設定來改變動畫顯示的位置。如果要同時在畫面上顯示數個下載中的動畫,則每一個動畫需建立一個 Standby 元件,並分別指定動畫顯示的位置。

範例

範例中建立了二個方形區域及三個按鈕,二個方形區域是用來展現 dojox/widget/Standby 的功能。另外建立了三個按鈕,一個用來顯示下載中的動畫,一個用來取消動畫,第三個按鈕用來在二個方形區域中切換動畫顯示的位置。

CSS

<style>
html {
    width:100%;
    height:100%;
} 
body {
    margin: 0 auto;
    width:1000px;
    height: 100%;
    padding: 20px;
}
</style>

沒有特別的樣式需要定義。

HTML

<body class="claro">
 
    
    <br>
    
<br>
</body>

Script


第 16~18 行建立一個 Standby 的元件。
target 指定動畫要遮蔽的區域,必須給一個 id 值,或是一個 dom node。
image 指定動畫的來源,可以用來改變預設的動畫。但要注意的是,如果動畫的尺寸大於要遮蔽的區域,就會看不到動畫了。預設的動畫只有 32 x 32 的大小。
color 指定動畫遮蔽膜的顏色。
duration 指定動畫在顯示及隱藏時所運作的時間,以 ms(千分之一秒)為單位。

第 26 行的寫法看起來有點奇怪,這是因為 standby.target 的值,在經過 dojo 的處理後,變成了一個 dom node,所以要讀取原來的 string 值時,必須寫成 standby.get("target").id,單純的寫 standby.get("target") 時,只會讀到一個 dom node。

第 23~28 行是切換動畫顯示位置的函式。

2015年10月11日 星期日

dijit/form/CheckBox

dijit/form/CheckBox

簡介

dijit/form/CheckBox 是除了dijit/form/Radiobutton 之外,另一種讓使用者一眼看到所有選項的介面元件。不同的是:

  1. dijit/form/RadionButton 是單選,所有選項只能撰擇其中一項,而 dijit/form/CheckBox 是複選,可以選擇多個選項,甚至全選。
  2. 兩者另一個不同點在 dijit/form/RadioButton 的介面是一個圓形按鈕,而 dijit/from/CheckBox 的介面是一個方形的檢核框。
  3. 同一組的 dijit/form/RadioButton 的 "name" 屬性值都相同,而 dijit/form/CheckBox 則每個元件的 name 屬性值都不同。

範例

範例中展示了兩組 CheckBox 的選項,一組用宣告法建立,另一組用程式法建立。兩組都放在一個 dojox/form/Manager 的容器中,由 form Manager 管理。另建置按鈕一個,按下按鈕時,在「開發者工具」的「主控台」中,會顯示選擇的結果。

CSS

<style>
html {
    width: 100%;
    height: 100%;
}
body {
    margin: 0 auto;
    width:1000px;
    height:100%;
    padding:20px;
}
</style>

沒有特別的樣式需要設定。

HTML

<body class="claro">
Fruit


Drink
</body>

第 5~9 行用宣告法建立三個 CheckBox
第 14~16 行放置二個 CheckBox 的掛載點。注意每個 <input> 標記中的 "name" 屬性值都不相同。

Script


第 20~27 行用程式法建立二個 CheckBox 各自掛載到相對的位置上。
第 30~31 行將兩個用程式法建立的 CheckBox 註冊到 form manager,讓 form manager 知道還有這兩個 dijit 要管。不然會讀取不到選擇值。
第 37 行展示另一種在按鈕被點按 (click) 時,要執行動作的另一種寫法。
第 38 行利用 form manager dijit 的 gatherFormValues() 函式,收集所有輸入資料,並將其顯示在主控台中。所有被選定的 CheckBox 的傳回值都是 true,沒有被選擇的傳回值則都是 fasle。
宣告法中的 CheckBox 並沒有設定預設要選定哪一個選項,如果使用者都沒有選,則 gatherFormValues() 函式中的各項資料的值都是 false。

dijit/form/RadioButton

dijit/form/RadioButton

簡介

dijit/form/RadioButton 的作用是在眾多的選項中挑選一個,和 dijit/form/Select 的作用很類似。在選項不多的情況下, RadioButton 可以一次把選項都顯示在畫面上,所有選項一目瞭然,使用者可以立刻進行挑選,比較有效率。但如果選項過多時,畫面上會顯得有點雜亂,反而不美。同一組的 RadioButton 中,使用者只能單選,也就是說,只能挑選其中一個選項。

範例

範例中展示了兩組 RadioButton 的選項,一組用宣告法建立,另一組用程式法建立。兩組都放在一個 dojox/form/Manager 的容器中,由 form Manager 管理。另建置按鈕一個,按下按鈕時,在「開發者工具」的「主控台」中,會顯示選擇的結果。

CSS

<style>
html {
    width: 100%;
    height: 100%;
}
body {
    margin: 0 auto;
    width:1000px;
    height:100%;
    padding:20px;
}
</style>

沒有特別的樣式需要設定。

HTML

<body class="claro">
    
Fruit <br> <br>
<br>
Drink
<br>
</body>

第 5~9 行用宣告法建立三個 RadioButton
第 15~17 行放置二個 RadioButton 的掛載點。注意每個 <input> 標記中的 "name" 屬性值都是一樣的。

Script


第 22~31 行用程式法建立二個 RadioButton 各自掛載到相對的位置上。
第 34~35 行將兩個用程式法建立的 RadioButton 註冊到 form manager,讓 form manager 知道還有這兩個 dijit 要管。不然會讀取不到選擇值。
第 37 行展示另一種在按鈕被點按 (click) 時,要執行動作的另一種寫法。
第 38 行利用 form manager dijit 的 gatherFormValues() 函式,收集所有輸入資料,並將其顯示在主控台中。
宣告法中的 RadioButton 並沒有設定預設要選定哪一個選項,如果使用者都沒有選,則 gatherFormValues() 函式中的資料 "fruit" 的值會是一個空字串。

2015年10月10日 星期六

dijit/form/Select

dijit/form/Select

簡介

dijit/form/Select 是下拉式選單介面元件的其中一種,當輸入值冗長,或後台資料庫的欄位值是以代碼儲存時,讓使用者便於輸入的一個良好選擇。 選單中的選項較多時,通常會經過排序,讓使用者容易找到選項;當選項不多時,則依選項使用率的高低,由上至下排列。

範例

範例中同時例示了dijit/form/Select 的宣告法和程式法兩種寫法。在程式法的範例中,又同時展示了 dijit/form/Select 使用 dojo/store/Memory 做為資料來源的寫法,以及如何動態改變選單的選項內容。在程式法中,另建立了一個按鈕,按下按鈕即會改變選單的選項內容。

dijit/form/Select 在預設的狀態下,選單輸入欄位的寬度會依照選單內容的寬度做改變(看宣告法的範例,就會看出來)。這一點在排版時會造成很大的困擾,使用者在輸入時,欄位的寬度一直在變化,對使用者經驗也不佳。採用時,最好幫選單定一個固定的寬度。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body {
    margin: 0 auto;
    width:1000px;
    height:100%;
    padding:20px;
}
</style>

無須定義特別的樣式。

HTML

<body class="claro">
    
Declative

Programmtic
</body>

第 4~8 行用宣告法定義了一個下拉式選單,並沒有設定其寛度,這樣可以看出欄位會隨選項的寬度改變。此時傳回的值會是屬性 value 的值。
第 14 行則建立一個 dijit 的掛載點,掛載由程式法建立出來的 dijit。
第 15 行則是按鈕的掛載點。

Script


第 21~25 建立按鈕,預設資料來源是 store1,在點按時,呼叫 app.changeStore 函式。同時用 style 定義了 Select 欄位的寬度為 150px。
labelAttr 指定要用 store 中的哪個鍵的名稱做為選項名。
sortByLabel 設定為 false,指定不要依選項名做排序。預設狀態下,會依 label 的名稱排序。
maxHeight 設定下拉式選單的最大高度,以 px 為單位,選項內容超過此高度時,會自動產生捲動軸。設定為 -1 時,會延伸高度至最大值。 第 41~46 行建立第一個 Memory store 做為 Select 的預設資料來源。此時傳回的選項值是 id 鍵的值。
第 48~55 行建立第二個 Memory store 做為 Select 要動態變更的選單內容來源。傳回的選項值亦是 id 鍵的值。

第 57~59 行是變更 Select 資料來源的函式,使用 Select 元件的 set() 函式改變 store 鍵的值,以改變選單內容。

2015年10月9日 星期五

dijit/Menu

dijit/Menu

簡介

dijit/Menu 配合 dijit/MenuItem 可以很快的建立一個簡單的選單。依據需求,選單可以常駐在畫面上;或當游標移到某一元件上方,按下滑鼠右鍵時才出現。這種在特定元件上按下右鍵才出現的選單,統稱為「內文選單」(context menu),因為選單的選項常常會依元件的性質或元件的內文而改變。

範例

範例中用程式法在畫面上建立一個顏色方塊,當游標移到方塊內並按下右鍵時,會出現一個有三個功能的內文選單。

CSS

<style>
html {
 width:100%;
 height:100%;
}
body {
    width:1000px;
    height:100%;
    margin: 0 auto;
    padding: 20px;
}
.box {
    width:100px;
    height:100px;
    border: 2px solid gray;
    background-color:#90EE90;
}
</style>

在 CSS 中,用 .box 設定方塊的樣式。

HTML

<body class="claro">
    
</body>

HTML 中的元件,此時並非 dijit/Menu 元件的掛載點,而是 dijit/Menu 指定要關聯的元件。dijit/Menu 可同時關聯多個元件,當游標在任何關聯的元件上按下右鍵,都會出現相同的內文選單。唯此時須用 event 物件去判斷觸發事件的元件,以決定針對哪個元件進行處理。

Script


第 20~21 行建立一個 dijit/Menu 元件做為容器,以容納選單中的選項,其中的 targetNodeIds 屬性值是一個陣列,陣列中包含該選單所有要關聯的對象,在範例中只有一個要關聯的對象,所以陣列中只有一個元素。

第 26~44 行則依序在容器中加入二個選項,一條分隔線,再加入一個選項,就大功告成了。

2015年10月8日 星期四

dijit/MenuBar

dijit/MenuBar

簡介

在應用系統中,建立一組結構化的選單系統,讓使用者可以迅速找到所要使用的功能,似乎是一件無法避免的工作。dojo 針對這個需求,也提供了各式的選單元件來應付。dijit/menuBar 可以應付複雜但結構化的選項,一般被用來作為應用系統的主選單。

範例

範例是一個橫式結構化的主選單,選項不多,但足以展示一般主選單所需要的結構了。整個主選單共有三層,以宣告法的方式建立,比較容易看出主選單的結構。

CSS

<style>
html {
    width:100%;
    height:100%;
}
body {
    width:1000px;
    height:100%;
    margin: 0 auto;
    padding:20px;
}
</style>

範例中採用 claro 預設的樣式,所以沒有特別需要設定的樣式。

HTML

<body class="claro">
 
</body>

在 HTML 中,最需要注意的是各種不同 Menu 及 MenuItem 所在的位置;還有哪些地方要呼叫動作 (action) 函式以採取必要的動作。

首先要建立一個 dijit/MenuBar 做為容器以容納第一層的選項。如果沒有第二層選項的項目,需使用 dijit/MenuBarItem (第 27 行)。如果該項目有第二層的選項,則必須使用 dijit/PopupMenuBarItem 元件(第 4 行和第 14 行)。元件中再建立 dijit/DropDwonMenu 元件做為容器來容納第二層的項目。

第 10 行的 dijit/MenuSeparator 元件是選頁分隔線,用來在某一層選項中,做項目的分類。

在第二層的項目中,如果沒有第三層選項,需使用 dijit/MenuItem 元件,若有第三層選項,則需使用 dijit/PopupMenuItem 元件(第 17 行)。

第三層選項則使用 dijit/Menu 做為容器(第 19 行),內中包含 dijit/MenuItem 做為選擇項目。

Script


在範例中,所有的動作都用 alert() 函式來顯示哪一個選項被選擇了,所以只有呼叫 parser.parse() 這個剖析器函式外,也沒有其它的程式碼。在實際的應用系統中,則將 alert() 函式,置換成要呼叫的函式。

2015年10月7日 星期三

dgrid/OnDemandGrid

dgrid/OnDemandGrid

簡介

「表格和清單」一向是最複雜及最難處理的元件,而在實務應用系統中又無可避免。 SitePen 公司除了開發了 dstore 之外,還有一系列稱之為 dgrid 的表格、清單元件,供使用 dojo 的程式開發人員使用,完全免費,也算是功德無量。

dgrid/OnDemandGrid 是 Grid 系列中最常使用到的一個,它所具備的功能也足以應付一般系統的應用,所以用它來做範例。但要能將 Grid 用到精熟,到官方網站去好好爬爬文章,學習一下,是有絕對必要的。

範例

範例中用了 dstore/Memory 做為表格的資料來源,dstore 中尚有其它不同的 store 可以做為資料來源。

CSS

<head>


</head>

Grid 有它自已的樣式表,得把它納入到網頁中。

<style>

</style>
<style>
html {
    width:100%;
    height:100%;
}
body {
    width:1000px;
    margin: 0 auto;
    padding-top:20px;
}
/* scroller bar */
.dgrid .dgrid-scroller {
    position: relative;
    overflow: visible;
}
/* set up grid size */
#myGrid {
    width:500px;
    height:auto;
}
#myGrid .dgrid-cell {
    padding:2px 2px;
    vertical-align: middle;
    font-family:"courier";
}
/* define header styles */
#myGrid .dgrid-header .field-firstName {
    text-align:center;
}
#myGrid .dgrid-header .field-lastName {
    text-align:center;
}
#myGrid .dgrid-header .field-games {
    text-align:center;
}
/* define field styles */
#myGrid .dgrid-column-action{
    width:50px;
}
#myGrid .field-id {
    width: 40px;
    text-align:center;
}
#myGrid .field-firstName {
    width:150px;
}
#myGrid .field-lastName {
    width: 150px;
}
#myGrid .field-games {
    width: auto;    /* take the rest available space */
    text-align:right;
}
/* define row styles */
.dgrid-row-even.ui-state-default { 
    background-color: #FFFFFF; 
} 
.dgrid-row-odd.ui-state-default { 
    background-color: #90EE90; 
}
</style>

要定義一個外觀整齊漂亮的表格,樣式表會很複雜,這裡是一些常用到的例子。把 Grid 的 id (#myGrid) 加在前面是因為這樣不會影響到其它的表格,前面沒有加 id 的樣式,會影響到系統中所有的表格。

第 27~35 行定義欄位抬頭的樣式,將所有抬頭的文字置中。

第 37 行用的是 .dgrid-column-action 來定義樣式,因為這個欄位沒有抬頭,欄位中放置了一個刪除的圖像,所以在定義該欄位時,特別定義了一個 id 的屬性,這時該欄位會產生一個名為 dgrid-column-id 的 class,其中 id 即為欄位中 id 鍵的值。

定義各欄的屬性時,欄位的 class 名稱用 "field-name" ,其中 "name" 即為程式中定義 header 時,各欄位的 "field" 的值來取代。

第 55~60 行定義奇數列和偶數列的樣式,讓奇數列和偶數列用不同的背景顏色來顯示。

HTML

<body class="claro">
    
</body>

因為是用程式法建立表格,所以只要在 HTML 裡放個掛載點即可。

Script


這裡把所資料來源及表格抬頭都另用一個變數來儲存,這樣看起來比較清楚。在實務時,在修改表格內容時,也同時要修改 store 的內容,這樣會比較好處理。

第 34~66 行定義資料做為資料來源。

第 68~99 行定義表格的抬頭, 第欄因為要置放一個「刪除」的圖像按鈕,所以最為複雜。
id 定義欄位的辨識碼,在樣式表裡使用,因為該欄位並未對應資料中的某一欄位。
renderCell 的值是一個函式,用來定義所要放入欄位的內容,這裡放的是一個圖像按鈕的 dijit。
第 71 行傳入的戈戈竹數:
object 是該列所顯示的項目物件。
value 是當該欄位有對應到資料欄位時,該欄位的值,這裡沒有對應到資料欄位,所以傳入值也是該列的項目物件。
node 是該欄位的 HTML 節點。
options 這個傳入值還真不知道是做什麼用的。
第 72~80 行定義一個圖像按鈕的 dijit,並將它置入欄位中。
第 76~77 行,在修改完 store 中的資料後,要呼叫 grid 的 refresh() 函式,這樣畫面中的表格才會反映資料來源的改變。也就是說,每當 store 的內容改變之後,都要呼叫 grid 的 refresh() 函式,改變才能在畫面上顯示。

第 100 行建立一個表格 (OnDemandGrid),因為要在畫面上做分頁,所以要納入 Pagination 這個延伸套件。
collection 定義資料來源。
columns 定義表頭格式。
rowsPerPage 定義每一頁的列數。
minRowsPerPage 定義每次提出需求時,要下載的最小筆數,預設為 25 筆。
pageSizeOptions 定義每一頁列數的選項。

最後,別忘了呼叫 starup() 函式。