diff --git a/addons/web/static/src/js/views/abstract_controller.js b/addons/web/static/src/js/views/abstract_controller.js index deb7c37bb59..7f82d550425 100644 --- a/addons/web/static/src/js/views/abstract_controller.js +++ b/addons/web/static/src/js/views/abstract_controller.js @@ -107,6 +107,9 @@ var AbstractController = AbstractAction.extend(ControlPanelMixin, { */ on_attach_callback: function () { this.renderer.on_attach_callback(); + if (this.searchView) { + this.searchView.on_attach_callback(); + } }, /** * Called each time the controller is detached from the DOM. diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js index 8a779becdea..5f758953658 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -58,6 +58,7 @@ var KanbanController = BasicController.extend({ if (this.hasButtons && this.is_action_enabled('create')) { this.$buttons = $(qweb.render('KanbanView.buttons', {widget: this})); this.$buttons.on('click', 'button.o-kanban-button-new', this._onButtonNew.bind(this)); + this.$buttons.on('keydown',this._onButtonsKeyDown.bind(this)); this._updateButtons(); this.$buttons.appendTo($node); } @@ -220,6 +221,18 @@ var KanbanController = BasicController.extend({ }); } }, + /** + * Moves the focus from the controller buttons to the first kanban record + * + * @private + * @param {jQueryEvent} e + */ + _onButtonsKeyDown: function (e) { + switch(e.keyCode) { + case $.ui.keyCode.DOWN: + this.$('.o_kanban_record:first').focus(); + } + }, /** * @private * @param {OdooEvent} event diff --git a/addons/web/static/src/js/views/kanban/kanban_record.js b/addons/web/static/src/js/views/kanban/kanban_record.js index dfe62e3746e..072f4d41f27 100644 --- a/addons/web/static/src/js/views/kanban/kanban_record.js +++ b/addons/web/static/src/js/views/kanban/kanban_record.js @@ -23,6 +23,7 @@ var KanbanRecord = Widget.extend({ events: { 'click .oe_kanban_action': '_onKanbanActionClicked', 'click .o_kanban_manage_toggle_button': '_onManageTogglerClicked', + 'keydown' : '_onKanbanKeyDown', }, /** * @override @@ -283,7 +284,7 @@ var KanbanRecord = Widget.extend({ */ _render: function () { this._replaceElement(this.qweb.render('kanban-box', this.qweb_context)); - this.$el.addClass('o_kanban_record'); + this.$el.addClass('o_kanban_record').attr("tabindex",0); this.$el.data('record', this); if (this.$el.hasClass('oe_kanban_global_click') || this.$el.hasClass('oe_kanban_global_click_edit')) { @@ -504,6 +505,14 @@ var KanbanRecord = Widget.extend({ this.do_warn("Kanban: no action for type : " + type); } }, + _onKanbanKeyDown: function (event) { + switch (event.keyCode) { + case $.ui.keyCode.ENTER: + event.preventDefault(); + this._openRecord(); + break; + } + }, /** * Toggles the configuration panel of the record * diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer.js b/addons/web/static/src/js/views/kanban/kanban_renderer.js index 913a4257257..953ffcf7dd7 100644 --- a/addons/web/static/src/js/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/js/views/kanban/kanban_renderer.js @@ -88,6 +88,61 @@ var KanbanRenderer = BasicRenderer.extend({ start_quick_create: '_onStartQuickCreate', quick_create_column_updated: '_onQuickCreateColumnUpdated', }), + events:_.extend({}, BasicRenderer.prototype.events || {}, { + 'keydown .o_kanban_record' : '_onRecordKeyDown' + }), + _focusOnNextCard: function(currentCardElement) { + var nextCard = currentCardElement.nextElementSibling; + if (nextCard) { + nextCard.focus(); + } + }, + _focusOnPrevousCard: function(currentCardElement) { + var previousCard = currentCardElement.previousElementSibling; + if (previousCard && previousCard.classList.contains("o_kanban_record")) { //previous element might be column title + previousCard.focus(); + } + }, + _onRecordKeyDown: function(e) { + switch(e.which) { + case $.ui.keyCode.DOWN: + this._focusOnNextCard(e.currentTarget); + e.stopPropagation(); + break; + case $.ui.keyCode.UP: + this._focusOnPrevousCard(e.currentTarget); + e.stopPropagation(); + break; + case $.ui.keyCode.RIGHT: + var currentColumn = e.currentTarget.parentElement; + var nextColumn = currentColumn.nextElementSibling; + if (nextColumn) { + var allCardsOfNextColumn = nextColumn.getElementsByClassName('o_kanban_record'); + if (allCardsOfNextColumn.length) { + allCardsOfNextColumn[0].focus(); + } + } + else { + this._focusOnNextCard(e.currentTarget); + } + e.stopPropagation(); + break; + case $.ui.keyCode.LEFT: + var currentColumn = e.currentTarget.parentElement; + var previousColumn = currentColumn.previousElementSibling; + if (previousColumn) { + var allCardsOfPreviousColumn = previousColumn.getElementsByClassName('o_kanban_record'); + if (allCardsOfPreviousColumn.length) { + allCardsOfPreviousColumn[0].focus(); + } + } + else { + this._focusOnPrevousCard(e.currentTarget); + } + e.stopPropagation(); + break; + } + }, /** * @override @@ -132,6 +187,9 @@ var KanbanRenderer = BasicRenderer.extend({ addQuickCreate: function () { return this.widgets[0].addQuickCreate(); }, + giveFocus:function() { + this.$('.o_kanban_record:first').focus(); + }, /** * Toggle fold/unfold the Column quick create widget */ diff --git a/addons/web/static/src/less/kanban_dashboard.less b/addons/web/static/src/less/kanban_dashboard.less index adf67f31bf0..da8f0adac72 100644 --- a/addons/web/static/src/less/kanban_dashboard.less +++ b/addons/web/static/src/less/kanban_dashboard.less @@ -43,6 +43,14 @@ margin-bottom: 10px; } + &:focus, &:focus-within { + -webkit-box-shadow: 1px 1px 3px 0px rgba(0,0,0,1); + -moz-box-shadow: 1px 1px 3px 0px rgba(0,0,0,1); + box-shadow: 1px 1px 3px 0px rgba(0,0,0,1); + z-index: 1; // show the shadow on top of the previous & next cards in grouped mode + outline: none; + } + // ------- Generic layout adaptations ------- .container { width: 100%; diff --git a/addons/web/static/src/less/kanban_view.less b/addons/web/static/src/less/kanban_view.less index b9eec962eaf..f9130469665 100644 --- a/addons/web/static/src/less/kanban_view.less +++ b/addons/web/static/src/less/kanban_view.less @@ -154,6 +154,13 @@ @media (max-width: @screen-xs-max) { padding: @o-kanban-inside-vgutter @o-kanban-inside-hgutter-mobile; } + &:focus, &:focus-within { + -webkit-box-shadow: 3px 3px 10px 0px rgba(0,0,0,1); + -moz-box-shadow: 3px 3px 10px 0px rgba(0,0,0,1); + box-shadow: 3px 3px 10px 0px rgba(0,0,0,1); + z-index: 1; // show the shadow on top of the previous & next cards in grouped mode + outline: none; + } } .o_kanban_quick_create { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 4a1bccc2850..ccd98c10962 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -203,7 +203,7 @@ + t-att-data-view-type="view.type" t-att-title="view.label" tabindex="-1"/> @@ -1033,7 +1033,7 @@