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; } } }); });