You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
380 lines
10 KiB
380 lines
10 KiB
define(["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, |
|
|
|
// allDayKeyboardUpDownUnit: Integer |
|
// Steps used during editing of an all day event using the keyboard and the up or down keys were pressed. |
|
allDayKeyboardUpDownUnit: "day", |
|
|
|
// allDayKeyboardUpDownSteps: 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, |
|
|
|
// allDayKeyboardLeftRightUnit: Integer |
|
// Steps used during editing of an all day event using the keyboard and the up or down keys were pressed. |
|
allDayKeyboardLeftRightUnit: "day", |
|
|
|
// allDayKeyboardLeftRightSteps: 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: String |
|
// 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.rendererManager.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); |
|
} |
|
}, |
|
|
|
_checkDir: function(dir, value){ |
|
return this.isLeftToRight() && dir == value || !this.isLeftToRight() && dir == (value=="left"?"right":"left"); |
|
}, |
|
|
|
_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._checkDir(dir, "left")){ |
|
steps = -steps; |
|
} |
|
|
|
var editKind = e[this.resizeModifier+"Key"] ? "resizeEnd" : "move"; |
|
|
|
var d = editKind == "resizeEnd" ? p.editedItem.endTime : p.editedItem.startTime; |
|
|
|
var newTime = d; |
|
var subColumn = p.editedItem.subColumn; |
|
|
|
if(editKind == "move" && this.subColumns && this.subColumns.length > 1){ |
|
var idx = this.getSubColumnIndex(subColumn); |
|
var updateTime = true; |
|
if(idx != -1){ |
|
if(this._checkDir(dir, "left")){ |
|
if(idx == 0){ |
|
subColumn = this.subColumns[this.subColumns.length-1]; |
|
}else{ |
|
updateTime = false; |
|
subColumn = this.subColumns[idx-1]; |
|
} |
|
}else if(this._checkDir(dir, "right")){ |
|
if(idx == this.subColumns.length-1){ |
|
subColumn = this.subColumns[0]; |
|
}else{ |
|
updateTime = false; |
|
subColumn = this.subColumns[idx+1]; |
|
} |
|
} |
|
if(updateTime){ |
|
newTime = this.renderData.dateModule.add(d, unit, steps); |
|
} |
|
} |
|
}else{ |
|
newTime = this.renderData.dateModule.add(d, unit, steps); |
|
} |
|
|
|
this._startItemEditingGesture([d], editKind, "keyboard", e); |
|
this._moveOrResizeItemGesture([newTime], "keyboard", e, subColumn); |
|
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.rendererManager.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; |
|
|
|
} |
|
|
|
} |
|
}); |
|
});
|
|
|