350 lines
9.8 KiB
JavaScript
350 lines
9.8 KiB
JavaScript
define("dojox/calendar/Keyboard", ["dojo/_base/array", "dojo/_base/lang", "dojo/_base/declare", "dojo/on", "dojo/_base/event", "dojo/keys"],
|
|
function(arr, lang, declare, on, event, keys){
|
|
|
|
return declare("dojox.calendar.Keyboard", null, {
|
|
|
|
// summary:
|
|
// This mixin is managing the keyboard interactions on a calendar view.
|
|
|
|
// keyboardUpDownUnit: String
|
|
// Unit used during editing of an event using the keyboard and the up or down keys were pressed. Valid values are "week", "day", "hours" "minute".
|
|
keyboardUpDownUnit: "minute",
|
|
|
|
// keyboardUpDownSteps: Integer
|
|
// Steps used during editing of an event using the keyboard and the up or down keys were pressed.
|
|
keyboardUpDownSteps: 15,
|
|
|
|
// keyboardLeftRightUnit: String
|
|
// Unit used during editing of an event using the keyboard and the left or right keys were pressed. Valid values are "week", "day", "hours" "minute".
|
|
keyboardLeftRightUnit: "day",
|
|
|
|
// keyboardLeftRightSteps: Integer
|
|
// Unit used during editing of an event using the keyboard and the left or right keys were pressed.
|
|
keyboardLeftRightSteps: 1,
|
|
|
|
// allDayKeyboardUpDownSteps: Integer
|
|
// Steps used during editing of an all day event using the keyboard and the up or down keys were pressed.
|
|
allDayKeyboardUpDownUnit: "day",
|
|
|
|
// allDayKeyboardUpDownUnit: String
|
|
// Unit used during editing of an all day event using the keyboard and the up or down keys were pressed. Valid values are "week", "day", "hours" "minute".
|
|
allDayKeyboardUpDownSteps: 7,
|
|
|
|
// allDayKeyboardUpDownSteps: Integer
|
|
// Steps used during editing of an all day event using the keyboard and the up or down keys were pressed.
|
|
allDayKeyboardLeftRightUnit: "day",
|
|
|
|
// allDayKeyboardLeftRightUnit: String
|
|
// Unit used during editing of an all day event using the keyboard and the left or right keys were pressed. Valid values are "week", "day", "hours" "minute".
|
|
allDayKeyboardLeftRightSteps: 1,
|
|
|
|
postCreate: function(){
|
|
this.inherited(arguments);
|
|
this._viewHandles.push(on(this.domNode, "keydown", lang.hitch(this, this._onKeyDown)));
|
|
},
|
|
|
|
// resizeModfier: "ctrl"
|
|
// The modifier used to determine if the item is resized instead moved during the editing on an item.
|
|
resizeModifier: "ctrl",
|
|
|
|
// maxScrollAnimationDuration: Number
|
|
// The duration in milliseconds to scroll the entire view.
|
|
// The scroll speed is constant when scrolling to show an item renderer.
|
|
maxScrollAnimationDuration: 1000,
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// Focus management
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
// tabIndex: String
|
|
// Order fields are traversed when user hits the tab key
|
|
tabIndex: "0",
|
|
|
|
// focusedItem: Object
|
|
// The data item that currently has the focus.
|
|
focusedItem: null,
|
|
|
|
_isItemFocused: function(item){
|
|
return this.focusedItem != null && this.focusedItem.id == item.id;
|
|
},
|
|
|
|
_setFocusedItemAttr: function(value){
|
|
if(value != this.focusedItem){
|
|
var old = this.focusedItem;
|
|
this._set("focusedItem", value);
|
|
this.updateRenderers([old, this.focusedItem], true);
|
|
this.onFocusChange({
|
|
oldValue: old,
|
|
newValue: value
|
|
});
|
|
}
|
|
if(value != null){
|
|
if(this.owner != null && this.owner.get("focusedItem") != null){
|
|
this.owner.set("focusedItem", null);
|
|
}
|
|
if(this._secondarySheet != null && this._secondarySheet.set("focusedItem") != null){
|
|
this._secondarySheet.set("focusedItem", null);
|
|
}
|
|
}
|
|
},
|
|
|
|
onFocusChange: function(e){
|
|
// summary:
|
|
// Event dispatched when the focus has changed.
|
|
// tags:
|
|
// callback
|
|
|
|
},
|
|
|
|
// showFocus: Boolean
|
|
// Show or hide the focus graphic feedback on item renderers.
|
|
showFocus: false,
|
|
|
|
_focusNextItem: function(dir){
|
|
// summary:
|
|
// Moves the focus to the next item in the specified direction.
|
|
// If there is no current child focused, the first (dir == 1) or last (dir == -1) is focused.
|
|
// dir: Integer
|
|
// The direction of the next child to focus.
|
|
//
|
|
// - 1: Move focus to the next item in the list.
|
|
// - -1: Move focus to the previous item in the list.
|
|
|
|
if(!this.renderData || !this.renderData.items || this.renderData.items.length == 0){
|
|
return null;
|
|
}
|
|
|
|
var index = -1;
|
|
var list = this.renderData.items;
|
|
var max = list.length - 1;
|
|
var focusedItem = this.get("focusedItem");
|
|
|
|
// find current index.
|
|
if(focusedItem == null){
|
|
index = dir > 0 ? 0 : max;
|
|
}else{
|
|
arr.some(list, lang.hitch(this, function(item, i){
|
|
var found = item.id == focusedItem.id;
|
|
if(found){
|
|
index = i;
|
|
}
|
|
return found;
|
|
}));
|
|
index = this._focusNextItemImpl(dir, index, max);
|
|
}
|
|
|
|
// find the first item with renderers.
|
|
var reachedOnce = false;
|
|
var old = -1;
|
|
|
|
while(old != index && (!reachedOnce || index != 0)){
|
|
|
|
if(!reachedOnce && index == 0){
|
|
reachedOnce = true;
|
|
}
|
|
|
|
var item = list[index];
|
|
|
|
if(this.itemToRenderer[item.id] != null){
|
|
// found item
|
|
this.set("focusedItem", item);
|
|
return;
|
|
}
|
|
old = index;
|
|
index = this._focusNextItemImpl(dir, index, max);
|
|
|
|
}
|
|
},
|
|
|
|
_focusNextItemImpl: function(dir, index, max){
|
|
// tags:
|
|
// private
|
|
|
|
if(index == -1){ // not found should not occur
|
|
index = dir > 0 ? 0 : max;
|
|
}else{
|
|
if(index == 0 && dir == -1 || index == max && dir == 1){
|
|
return index;
|
|
}
|
|
index = dir > 0 ? ++index : --index;
|
|
}
|
|
return index;
|
|
},
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// Keyboard
|
|
//
|
|
//////////////////////////////////////////////////////////
|
|
|
|
_handlePrevNextKeyCode: function(e, dir){
|
|
// tags:
|
|
// private
|
|
|
|
if(!this.isLeftToRight()){
|
|
dir = dir == 1 ? -1 : 1;
|
|
}
|
|
this.showFocus = true;
|
|
this._focusNextItem(dir);
|
|
|
|
var focusedItem = this.get("focusedItem");
|
|
|
|
if(!e.ctrlKey && focusedItem){
|
|
this.set("selectedItem", focusedItem);
|
|
}
|
|
|
|
if(focusedItem){
|
|
this.ensureVisibility(focusedItem.startTime, focusedItem.endTime, "both", undefined, this.maxScrollAnimationDuration);
|
|
}
|
|
},
|
|
|
|
_keyboardItemEditing: function(e, dir){
|
|
// tags:
|
|
// private
|
|
|
|
event.stop(e);
|
|
|
|
var p = this._edProps;
|
|
|
|
var unit, steps;
|
|
|
|
if(p.editedItem.allDay || this.roundToDay || p.rendererKind == "label"){
|
|
unit = dir == "up" || dir == "down" ? this.allDayKeyboardUpDownUnit : this.allDayKeyboardLeftRightUnit;
|
|
steps = dir == "up" || dir == "down" ? this.allDayKeyboardUpDownSteps : this.allDayKeyboardLeftRightSteps;
|
|
}else{
|
|
unit = dir == "up" || dir == "down" ? this.keyboardUpDownUnit : this.keyboardLeftRightUnit;
|
|
steps = dir == "up" || dir == "down" ? this.keyboardUpDownSteps : this.keyboardLeftRightSteps;
|
|
}
|
|
|
|
if(dir == "up" || !this.isLeftToRight() && dir == "right" ||
|
|
this.isLeftToRight() && dir == "left"){
|
|
steps = -steps;
|
|
}
|
|
|
|
var editKind = e[this.resizeModifier+"Key"] ? "resizeEnd" : "move";
|
|
|
|
var d = editKind == "resizeEnd" ? p.editedItem.endTime : p.editedItem.startTime;
|
|
|
|
var newTime = this.renderData.dateModule.add(d, unit, steps);
|
|
|
|
this._startItemEditingGesture([d], editKind, "keyboard", e);
|
|
this._moveOrResizeItemGesture([newTime], "keyboard", e);
|
|
this._endItemEditingGesture(editKind, "keyboard", e, false);
|
|
|
|
if(editKind == "move"){
|
|
if(this.renderData.dateModule.compare(newTime, d) == -1){
|
|
this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "start");
|
|
}else{
|
|
this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "end");
|
|
}
|
|
}else{ // resize end only
|
|
this.ensureVisibility(p.editedItem.startTime, p.editedItem.endTime, "end");
|
|
}
|
|
},
|
|
|
|
_onKeyDown: function(e){
|
|
// tags:
|
|
// private
|
|
|
|
var focusedItem = this.get("focusedItem");
|
|
|
|
switch(e.keyCode){
|
|
|
|
case keys.ESCAPE:
|
|
|
|
if(this._isEditing){
|
|
|
|
if(this._editingGesture){
|
|
this._endItemEditingGesture("keyboard", e, true);
|
|
}
|
|
|
|
this._endItemEditing("keyboard", true);
|
|
|
|
this._edProps = null;
|
|
}
|
|
break;
|
|
|
|
case keys.SPACE:
|
|
|
|
event.stop(e); // prevent browser shortcut
|
|
|
|
if(focusedItem != null){
|
|
this.setItemSelected(focusedItem, e.ctrlKey ? !this.isItemSelected(focusedItem) : true);
|
|
}
|
|
break;
|
|
|
|
case keys.ENTER:
|
|
|
|
event.stop(e); // prevent browser shortcut
|
|
|
|
if(focusedItem != null){
|
|
|
|
if(this._isEditing){
|
|
this._endItemEditing("keyboard", false);
|
|
}else{
|
|
|
|
var renderers = this.itemToRenderer[focusedItem.id];
|
|
|
|
if(renderers && renderers.length > 0 && this.isItemEditable(focusedItem, renderers[0].kind)){
|
|
|
|
this._edProps = {
|
|
renderer: renderers[0],
|
|
rendererKind: renderers[0].kind,
|
|
tempEditedItem: focusedItem,
|
|
liveLayout: this.liveLayout
|
|
};
|
|
|
|
this.set("selectedItem", focusedItem);
|
|
|
|
this._startItemEditing(focusedItem, "keyboard");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case keys.LEFT_ARROW:
|
|
|
|
event.stop(e); // prevent browser shortcut
|
|
|
|
if(this._isEditing){
|
|
this._keyboardItemEditing(e, "left");
|
|
}else{
|
|
this._handlePrevNextKeyCode(e, -1);
|
|
}
|
|
break;
|
|
|
|
case keys.RIGHT_ARROW:
|
|
|
|
event.stop(e); // prevent browser shortcut
|
|
|
|
if(this._isEditing){
|
|
this._keyboardItemEditing(e, "right");
|
|
}else{
|
|
this._handlePrevNextKeyCode(e, 1);
|
|
}
|
|
break;
|
|
|
|
case keys.UP_ARROW:
|
|
if(this._isEditing){
|
|
this._keyboardItemEditing(e, "up");
|
|
}else if(this.scrollable){
|
|
this.scrollView(-1);
|
|
}
|
|
break;
|
|
|
|
case keys.DOWN_ARROW:
|
|
if(this._isEditing){
|
|
this._keyboardItemEditing(e, "down");
|
|
}else if(this.scrollable){
|
|
this.scrollView(1);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
});
|
|
});
|