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() 函式。

2015年10月6日 星期二

dstore/Memory

dstore/Memory

簡介

dstore 由 SitePen 公司所開發,這個套件可以配合 dojo 1.8.1 以上的版本使用,而 dojo 2.0 則計劃採用其 API (Application Program Interface) 做為標準介面。倘若沒有舊有程式的包袱,可以直接學習這個套件的 API,免得多花工夫。

範例

範例中建立了一個 Memory store,基本上就是一個本地資料庫的概念,因為不是使用者介面的元件,所以 CSS 及 HTML 都用不到。程式中例出了fetch, fetchRange, filter, sort, get, add, put, Remove 等等用法做為參考。

CSS

<style>
</style>

不須定義樣式。

HTML

<body class="claro">

Nothing to show here! Check the Console!

</body>

dstore/Memory 本身不是介面元件,所以在 HTML 裡只放一條訊息,提醒要打開「開發者工具」的「主控台」去看執行結果。

Script


第 13 ~ 28 行建立 Memory Store。
第 26 行 idProperty:"id" 指定物件中的 id 鍵值做為唯一辨認物件的鍵值 (primary key)。
第 27 行 data:nList 指定變數 nList 做為資料來源。如果不想另外定義一個變數,直接把物件陣列寫在 data: 後也可以。

大部份的程式碼及其作業都很簡單,只要有點 Javascript 的基礎,應該都看得懂。只有幾個地方要特別注意:
fetchRange 的 start 和 end 兩個設定,用的是 Javascript 中陣列的索引值 (index),所以第一筆資料的索引值是由 0 開始。具有定義在 end 的那個索引值的物件不會被傳回來,也就是說範例中 {start:5, end:7} 的設定,只會傳回陣列中第 5 個和第 6 個物件,第 7 個物件不包含在傳回值中。
第 87 ~ 95 行寫得長一點,仔細看一下,就能瞭解是先取得一個物件,變更物件的資料;變更物件的資料後,記得要用 put() 函式去修改 Memory store 中的資料,最後確認 Memory store 中的資料有被成功變更。

2015年10月5日 星期一

dojox/widget/DialogSimple

dojox/widget/DialogSimple

簡介

dojo 裡本來就提供了一個 dijit/Dialog ,為何又要提供一個 dojox/widget/DialogSimple 呢?實際上,dojo 中提供了很多不同的 Dialog (對話框),不同的 Dialog 各有不同的功能及用途,有的 Dialog 在外觀上有明顯的不同。digit/Dialog 和 dojox/widget/DialogSimple 在外觀上完全一樣,不同的是 dijit/Dialog 繼承了 dijit/layout/ContentPane,而 dijix/widget/DialogSimple 繼承了 dojox/layout/ContentPane,當引入外部網頁做為 Dialog 的內容時,一樣可以執行附加在外部網頁中的 Javascript 程式碼,在所以在功能上比 dijit/Dialog 要強。因為繼承了 dojox/layout/ContentPane,所以在 dojox/layout/ContentPane 能做的事情,在 dojox/widget/DialogSimple 都可以套用。

dijit/Dialog 或是 dojox/widget/DialogSimple 都一樣,最特殊的一點是,當使用宣告法時,不論把 Dialog 或 DialogSimple 放在網頁的何處,最終的 HTML 碼裡,Dialog 或 DialogSimple 的 HTML 碼都會被提升至 <body> 標記的下方,成為 <body> 的直接子節點。當使用程式法時,不論 Dialog 的掛載點在何處,也是一樣的結果。這是因為做為一個 modal 的元件,這兩個 Dialog 在顯示時,都會產生一個背景屏蔽,將其它螢幕上的元件遮住,阻止使用者採取其它行動,直到使用者對 Dialog 做出反應,才會在隱藏 Dialog 時,取消對螢幕的屏蔽。

範例

範例中先產生一個按鈕,按下按鈕後會顯示一個登入的 Dialog,在 Dialog 中,按下 OK 或是 Cancel 按鈕,亦或是按下右上角的 X 符號,都會隱藏 Dialog ,但不會做其它的動作。

CSS

<style>
.claro .dijitDialogUnderlay {
    background-color:lightgreen;
    opacity:0.5;
}
.dijitDialogPaneContentArea {
    min-width: 300px;
    min-height: 200px;
}
</style>

如果不喜歡預設屏蔽的顏色或是透明度,可以藉由更改 .claro .dijitDialogUnderlay 的 background-color 或 opacity 屬性,以逹到要求。
如果希望 Dialog 不論內容的多寡,都能至少維持一定的大小,最好是修改 .dijitDialogPaneContentArea 的 min-width 和 min-height 屬性的值。要注意的是這個值不含 .dijitDialogTitle 及 .dijitDialogPaneActionBar 的高度。

HTML

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

Dialog 的內容又分成兩大塊區域,一塊是 class="dijitDialogPaneContentArea" 的區域,這塊區域放置 Dialog 的內容。另一塊是 class="dijitdialogPaneActionBar" 的區域,這個區域放置使用者採取行動時的按鈕,它的區域底色有所不同。

Script


Javascript 的程式碼,只是單純的顯示 Dialog 及隱藏 Dialog ,沒有做其它特別值得一提的事情。

2015年10月4日 星期日

dijit/layout/BorderContainer

dijit/layout/BorderContainer

簡介

dijit/layout/BorderContainer 是 dojo 針對網頁應用畫面的設計,所提供眾多佈置的其中一種,BorderContainer 是其中應用的最廣泛的一種佈置,而且最常被用套在應用系統的主畫面上。BorderContainer 的佈置又分為 headline 及 sidebar 二形態。基本上,二者都將螢幕分割成,上(top)、下 (bottom)、左 (left)、右 (right) 及中央 (center) 五大區塊。其中,只有中央區塊一定要定義,其它區塊則是選項;也可以有多個相同位置的區塊,例如兩個上方的區塊,或是二個左方的區塊,在佈置上非常具有彈性。每個區塊都由 dijit/layout/ContentPane 或 dojox/layout/ContentPane 所構成,因此,可以依需求不論是直接改變,或是引入外部的網頁以改變個區塊中的內容,。

範例

headline

當 design 屬性設定為 "headline" 時,上方、下方的橫幅會橫跨整個有效寬度,範例中 CSS 中的 width 設定為 1000px。

sidebar

當 design 屬性設定為 "sidebar" 時,左、右的直欄會佔據整個有效高度,範例中 CSS 中的 height 設定為 100%。

CSS

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

將 body 的寬度設為 1000px ,並將其置於螢幕左右的中間。

HTML

<body class="claro">
Top 1
Top 2
Left
Right
Center
Bottom
</body>

設定 BorderContainer 和各個 ContentPane 的掛載點,注意 ContentPane 的掛載點都包含在 BorderContainer 的<div></div> 的標記對中。

Script


BorderContainer 的屬性有:
design: 設定佈置的形態,有 "headline" 及 "sidebar" 兩個值可供選擇。
gutters: 設定各 ContentPane 的邊框之間是否要有間隔。
liveSplitters: 設定各 ContentPane 移動把手是否在移動時,以動畫方式立即顯示。

ContentPane 的屬性有:
region: 設定 ContentPane 的所在位置,每一個 ContentPane 都要設定。
spliter: 設定移動把手,如果有設定為 true,則該 ContentPane 可以利用移動把手改變高度,或改變寬窄。
minSizemaxSize: 當有設定移動把手時,可以加設該 ContentPane 的最小及最大的高度,或寬度。
各 ContentPane,除了中央那個,其它的都要用 style 設定寬度,或高度。上、下的 ContentPane 要設定高度,右、右的 ContentPane 要設定寬度。在將定義好尺寸的 ContentPane 依 region 中所定義擺定後,剩下的空間都歸中央的 ContentPane 所有。
在範例中,BorderContainer 和每一個 ContentPane 都在 style 屬性中,定義了邊框及邊框的顏色,這樣比較容易看清楚各 ContentPane 所佔據的位置。最後,別忘了呼叫 BorderContainer 的 startup() 函式。

2015年10月3日 星期六

dojox/layout/ContentPane (part II)

dojox/layout/ContentPane (part II)

簡介

dojox/layout/ContentPane 在下載新內容以更換窗格的內容時,還提供了五個回呼函式,對應五種觸發事件。這五個函式分別是:

  1. onDownloadStart()
  2. onUnload()
  3. onLoad()
  4. onDownloadEnd()
  5. onDownloadError()

當設定 "content" 屬性直接改變內容時,只會觸發並執行 onUnload() 及 onLoad() 兩個函式。而在引入外部的網頁時,則會觸發並依序執行 onDownloadStart()、onUnload()、onLoad() 及 onDownloadEnd() 四個函式,onDownloadError() 只有在下載外部網頁發生錯誤時才會觸發和執行。

其中,onDownloadStart() 這個函式要特別注意,它一定要回傳 (return) 一個字串,根據 dojo 的說明文件,這個字串是用來做為下載訊息之用,如果沒有回傳一個字串,會引發錯誤。切記!切記!

範例

這個範例也是建立兩個按鈕及一個窗格,第一個按鈕直接改變內容,第二個按鈕則從外部引入網頁。執行時會用彈出視窗顯示正在執行的步驟,請同時注意窗格中內容的變化,藉以瞭解函式執行的時機。

CSS

<style>
html{
  width:100%;
  height:100%;
}
 body {
  margin:0 auto;
  width:1000px;
  height:100%;
  padding:0;
  overflow:hidden;
}
#mainCP {
  width:400px;
  height:400px;
  border: 1px solid gray;
}
</style>

CSS 的主要目的只是在把按鈕和窗格移到中間,比較容易觀看及操作。

HTML

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

Script


onUnload() 會在原始內容被清除前執行,此時原始內容的節點 (node) 和 dijit 都還在,如果要針對這些節點和 dijit 做一些事,包括清除事件監聽的機制等等,都可以在此時完成,隨後節點和 dijit 就被清除了。

2015年10月2日 星期五

dojox/layout/ContentPane (part I)

dojox/layout/ContentPane (part I)

簡介

dojox/layout/ContentPane 是 dijit/layout/ContentPane 的子類別 (subclass) 但實在比 dijit/layout/contentPane 好用多了。內容窗格 (ContentPane) 主要的作用是在流覽器的螢幕上畫分一塊區域,在這區域中可以依實務需要改變窗格的內容。窗格的內容可以是一段純文字、一段 HTML 碼,甚至可以是另一個網頁。

在這一篇先展示如何將一段 HTML 碼,放到窗格中。以改變窗格的內容。如果窗格要引入另一個網頁時,因為 Chrome 的預設會阻擋流覽器讀取本地 (local) 的檔案,所以得先把 Chrome 關掉,在 OS X 的主控台下 "open /Applications/Browser/Google\ Chrome.app --args --allow-file-access-from-files" 指令,在 windows 的主控台下 "Chrome.exe --allow-file-access-from-files",記得在下指令前,一定要把所有的開啟的 Chrome 流覽器都關掉,不然指令會不起作用。

範例

範例中建立兩個按鈕,及一個大小為 400px * 400px 的窗格,按下其中一個按鈕便會改變窗格的內容。

CSS

<style>
html {
 width:100%;
 height:100%;
} 
body {
 margin:0 auto;
 width:1000px;
 height:100%;
 padding:20px;
}
#mainCP {
 width:400px;
 height:400px;
 border: 1px solid gray;
}
</style>

CSS 的設定主要在把按鈕和窗格移到螢幕中間。窗格也設定了邊框,好看見窗格的大小。

HTML

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

第 4 行用宣告法宣告了一個窗格,其樣式在 CSS 中用 #mainCP{} 設定好了。


設定窗格 "content" 屬性的值,便可以改變窗格內容,傳入函式的第二個參數,便是所要顯示在窗格中的內容,在第 18 行,傳入的是一段純文字。在第 21 行,則傳入一段 HTML 碼。

如果窗格要改變的內容來自另外一個檔案,或是網頁,則要多設定幾個窗格的屬性,將 HTML 碼修改如下:

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

adjustPath:true 設定要修正檔案路徑,有時被引入的網頁和含有窗格的網頁並不在同一個目錄下,在被引入的網頁中,所果含有相對路徑的參考值時,會找不到路徑,設定這個屬性會修正相對路徑的參考值,變成都是以窗格所在的目錄作為相對路徑的起始目錄。所以在被引入的網頁中,要以窗格的所在目錄做為相對路徑參考值的起始目錄。如果被引入的網頁中,採取的是絕對路徑的參考值,就不會受到影響了。

cleanContent:true 設定,只有在引入的網頁是個完整的網頁,包含有<!DOCTYPE html>、 <html>、<head> 等標記時有作用,其作用是將上述的標記去除,免得造成網頁的混亂。

renderStyle:true 設定會讀取被引入網頁中的 <style> 標記,並將其中的樣式套用到整個網頁中。因此,在要被引用的網頁中設定樣式時,要很小心。盡可能不要改變標記的樣式,否則會造成非預期的效果,可能會改變到窗格外的其它元件。套用樣式時,最好能盡可能詳細指定要套用樣式的元件。

Script


要引入外部網頁時,所要改變的窗格屬性是 "href",第二個參數要傳入網頁的所在目錄位置和檔名。在範例中,假設被引入的網頁和含有窗格的網頁處在相同的目錄下。

2015年10月1日 星期四

dojo/request (AJAX)

dojo/request

簡介

dojo/request 是 dojo toolkit 的 AJAX 模組,用來傳送符合 AJAX 規範的 request 給後端伺服器,要求伺服器傳送資料給流覽器。

這篇先介紹如何使用 get 和 post 兩種,接收的檔案是標準的文字檔。因為沒有真的伺服器在後端,所以就放一個檔案在目錄裡,直接去讀這個檔案。但是 Chrome 的預設會阻擋流覽器讀取本地 (local) 的檔案,所以得先把 Chrome 關掉,在 OS X 的主控台下"open /Applications/Browser/Google\ Chrome.app --args --allow-file-access-from-files" 指令,在 windows 的主控台下 "Chrome.exe --allow-file-access-from-files",記得在下指令前,一定要把所有的開啟的 Chrome 流覽器都關掉,不然指令會不起作用。

範例

範例中建立兩個按鈕,一個按下後會送出 get 的 request,另一個會送出 post 的 request,但接收的檔案都是同一個;把資料檔和網頁放在同一個目錄下就可以了。資料檔的檔名為 lyrics.txt。記得開啟「開發者工具」中的「主控台」看結果。如果真的送資料到伺服器, url 的值就要填提供服務的 servlet 或 CGI (Common Gatway Interface) 程式的名稱了。

CSS

<style>
input, textarea {
    font-family:monospace;
}
</style>

在 CSS 中改變 input 及 textarea 兩毎標記內容所使用的字型,改用定寬字。

HTML

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

Script


第 18 行和第 42 行指派給變數 query 的值,就當成由輸入欄位取得,透過 dojos/form/Manager 的 gatherFormValues() 所傳回的 Javascipt 物件,當成送到伺服器的查詢資料。

變數 opts 的值也是個 Javascript 的物作,其中的屬性用來設定 request 的選項。

method 指定 request 所使用的方法,其實共有八種如下:

  1. OPTIONS
  2. GET
  3. HEAD
  4. POST
  5. PUT
  6. DELETE
  7. TRACE
  8. CONNECT
這裡只介紹 GET 和 POST 兩種,其它六種各有不同的用途。

GET 和 POST 選項不同的地方在 GET 用 query 鍵傳送資料給伺服器,query 的值會被轉成 query string 的格式,附加在 url 的後面,傳給伺服器。POST 則用 data 鍵,傳送資料給伺服器, url 的後面不會加任何東西。

async:true 是預設值,指 AJAX request 會以非同步的方式傳送,如果程式一定要等到收到伺服器傳回的資料後才能開始做其它事,就要把它設定為 false,改為同步作業。

preventCache:true, 告訴流覽器不要使用快取 (cache) 中的資料,每次都要向伺服器要資料。如果後端資料變更的頻率很高時,最後設定為 true,避免使用 cache 中的資料,如果資料很少在變動,設定為 false 可以節省頻寬,而且反應會比較快。

timeout 設定逾時值,單為為 milliseconds。設這個值和網路的頻寬有關,最好實地實驗,測一下。

handlAs 指定傳回的資料要以何種格式進行處理。支援的格式有下列幾種:

  1. text
  2. json
  3. javascript
  4. xml

設定為 text 時,直接傳回純文字。

設定為 json 時,若收到的資料確實為 JSON 格式時,會轉成 Javascrpt 的物件後傳回。

設定為 javascript 時,若收到正確的 Javascript,則下載後會立刻執行該段 Javascript 程式碼。但這很有可能造成安全上的漏洞,要小心使用。

設定為 xml 時,則傳回一份 XML 文件,以供處理。

request 的回呼函式有三個傳入的參數都不同。第一個回呼函式是成功時呼叫,參數是伺服器傳回的資料。第二個是發生錯誤時呼叫,傳入的參數是含有錯誤訊息的物件。第三個函式在每一次傳回回應 (response)時呼叫一次;有時一個 request 會有一個以上的 response,可以物件裡的資料來顯示傳輸進度。