From 378d10b748f71311e661cbbc722ea8f393294711 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Fri, 20 May 2016 05:17:21 -0400 Subject: [PATCH] Fix bug where message list columns could be in wrong order after column drag-n-drop and list sorting --- program/js/list.js | 501 +++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 333 insertions(+), 168 deletions(-) diff --git a/program/js/list.js b/program/js/list.js index 895a9e6..9b0bd9a 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -1,26 +1,40 @@ -/* - +-----------------------------------------------------------------------+ - | Roundcube List Widget | - | | - | This file is part of the Roundcube Webmail client | - | Copyright (C) 2006-2013, The Roundcube Dev Team | - | | - | Licensed under the GNU General Public License version 3 or | - | any later version with exceptions for skins & plugins. | - | See the README file for a full license statement. | - | | - +-----------------------------------------------------------------------+ - | Authors: Thomas Bruederli <roundcube@gmail.com> | - | Charles McNulty <charles@charlesmcnulty.com> | - +-----------------------------------------------------------------------+ - | Requires: common.js | - +-----------------------------------------------------------------------+ -*/ +/** + * Roundcube List Widget + * + * This file is part of the Roundcube Webmail client + * + * @licstart The following is the entire license notice for the + * JavaScript code in this file. + * + * Copyright (c) 2005-2014, The Roundcube Dev Team + * + * The JavaScript code in this page is free software: you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License (GNU GPL) as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. The code is distributed WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. + * + * As additional permission under GNU GPL version 3 section 7, you + * may distribute non-source (e.g., minimized or compacted) forms of + * that code without the copy of the GNU GPL normally required by + * section 4, provided you include this license notice and a URL + * through which recipients can access the Corresponding Source. + * + * @licend The above is the entire license notice + * for the JavaScript code in this file. + * + * @author Thomas Bruederli <roundcube@gmail.com> + * @author Charles McNulty <charles@charlesmcnulty.com> + * + * @requires jquery.js, common.js + */ /** * Roundcube List Widget class - * @contructor + * @constructor */ function rcube_list_widget(list, p) { @@ -32,16 +46,12 @@ this.list = list ? list : null; this.tagname = this.list ? this.list.nodeName.toLowerCase() : 'table'; this.id_regexp = /^rcmrow([a-z0-9\-_=\+\/]+)/i; - this.thead; - this.tbody; - this.fixed_header; - this.frame = null; this.rows = {}; this.selection = []; this.rowcount = 0; this.colcount = 0; - this.subject_col = -1; + this.subject_col = 0; this.modkey = 0; this.multiselect = false; this.multiexpand = false; @@ -50,12 +60,14 @@ this.column_movable = false; this.keyboard = false; this.toggleselect = false; + this.aria_listbox = false; + this.parent_focus = true; this.drag_active = false; this.col_drag_active = false; this.column_fixed = null; - this.last_selected = 0; - this.shift_start = 0; + this.last_selected = null; + this.shift_start = null; this.focused = false; this.drag_mouse_start = null; this.dblclick_time = 500; // default value on MS Windows is 500 @@ -65,6 +77,9 @@ if (p && typeof p === 'object') for (var n in p) this[n] = p[n]; + + // register this instance + rcube_list_widget._instances.push(this); }; @@ -84,6 +99,14 @@ this.tbody = this.list; } + if ($(this.list).attr('role') == 'listbox') { + this.aria_listbox = true; + if (this.multiselect) + $(this.list).attr('aria-multiselectable', 'true'); + } + + var me = this; + if (this.tbody) { this.rows = {}; this.rowcount = 0; @@ -91,16 +114,28 @@ var r, len, rows = this.tbody.childNodes; for (r=0, len=rows.length; r<len; r++) { - this.rowcount += this.init_row(rows[r]) ? 1 : 0; + if (rows[r].nodeType == 1) + this.rowcount += this.init_row(rows[r]) ? 1 : 0; } this.init_header(); this.frame = this.list.parentNode; // set body events - if (this.keyboard) + if (this.keyboard) { rcube_event.add_listener({event:'keydown', object:this, method:'key_press'}); + + // allow the table element to receive focus. + $(this.list).attr('tabindex', '0') + .on('focus', function(e){ me.focus(e); }); + } } + + if (this.parent_focus) { + this.list.parentNode.onclick = function(e) { me.focus(); }; + } + + return this; }, @@ -109,18 +144,24 @@ */ init_row: function(row) { + row.uid = this.get_row_uid(row); + // make references in internal array and set event handlers - if (row && String(row.id).match(this.id_regexp)) { - var self = this, - uid = RegExp.$1; - row.uid = uid; + if (row && row.uid) { + var self = this, uid = row.uid; this.rows[uid] = {uid:uid, id:row.id, obj:row}; - // set eventhandlers to table row - row.onmousedown = function(e){ return self.drag_row(e, this.uid); }; - row.onmouseup = function(e){ return self.click_row(e, this.uid); }; + $(row).data('uid', uid) + // set eventhandlers to table row (only left-button-clicks in mouseup) + .mousedown(function(e) { return self.drag_row(e, this.uid); }) + .mouseup(function(e) { + if (e.which == 1 && !self.drag_active) + return self.click_row(e, this.uid); + else + return true; + }); - if (bw.touch) { + if (bw.touch && row.addEventListener) { row.addEventListener('touchstart', function(e) { if (e.touches.length == 1) { self.touchmoved = false; @@ -140,6 +181,15 @@ e.preventDefault(); } }, false); + } + + // label the list row with the subject col as descriptive label + if (this.aria_listbox) { + var lbl_id = 'l:' + row.id; + $(row) + .attr('role', 'option') + .attr('aria-labelledby', lbl_id) + .find(this.col_tagname()).eq(this.subject_col).attr('id', lbl_id); } if (document.all) @@ -163,7 +213,7 @@ if (this.fixed_header) { // copy (modified) fixed header back to the actual table $(this.list.tHead).replaceWith($(this.fixed_header).find('thead').clone()); - $(this.list.tHead).find('tr td').attr('style', ''); // remove fixed widths + $(this.list.tHead).find('th,td').attr('style', '').find('a').attr('tabindex', '-1'); // remove fixed widths } else if (!bw.touch && this.list.className.indexOf('fixedheader') >= 0) { this.init_fixed_header(); @@ -176,7 +226,7 @@ if (this.column_fixed == r) continue; col = this.thead.rows[0].cells[r]; - col.onmousedown = function(e){ return p.drag_column(e, this); }; + col.onmousedown = function(e) { return p.drag_column(e, this); }; this.colcount++; } } @@ -190,17 +240,31 @@ if (!this.fixed_header) { this.fixed_header = $('<table>') .attr('class', this.list.className + ' fixedcopy') + .attr('role', 'presentation') .css({ position:'fixed' }) .append(clone) .append('<tbody></tbody>'); $(this.list).before(this.fixed_header); var me = this; - $(window).resize(function(){ me.resize() }); + $(window).resize(function() { me.resize(); }); + $(window).scroll(function() { + var w = $(window); + me.fixed_header.css({ + marginLeft: -w.scrollLeft() + 'px', + marginTop: -w.scrollTop() + 'px' + }); + }); } else { $(this.fixed_header).find('thead').replaceWith(clone); } + + // avoid scrolling header links being focused + $(this.list.tHead).find('a.sortcol').attr('tabindex', '-1'); + + // set tabindex to fixed header sort links + clone.find('a.sortcol').attr('tabindex', '0'); this.thead = clone.get(0); this.resize(); @@ -214,15 +278,17 @@ var column_widths = []; // get column widths from original thead - $(this.tbody).parent().find('thead tr td').each(function(index) { + $(this.tbody).parent().find('thead th,thead td').each(function(index) { column_widths[index] = $(this).width(); }); // apply fixed widths to fixed table header $(this.thead).parent().width($(this.tbody).parent().width()); - $(this.thead).find('tr td').each(function(index) { - $(this).css('width', column_widths[index]); + $(this.thead).find('th,td').each(function(index) { + $(this).width(column_widths[index]); }); + + $(window).scroll(); }, /** @@ -242,6 +308,7 @@ this.rows = {}; this.rowcount = 0; + this.last_selected = null; if (sel) this.clear_selection(); @@ -290,15 +357,19 @@ if (row.nodeName === undefined) { // for performance reasons use DOM instead of jQuery here var domrow = document.createElement(this.row_tagname()); + if (row.id) domrow.id = row.id; + if (row.uid) domrow.uid = row.uid; if (row.className) domrow.className = row.className; if (row.style) $.extend(domrow.style, row.style); - for (var domcell, col, i=0; row.cols && i < row.cols.length; i++) { + for (var e, domcell, col, i=0; row.cols && i < row.cols.length; i++) { col = row.cols[i]; domcell = document.createElement(this.col_tagname()); if (col.className) domcell.className = col.className; if (col.innerHTML) domcell.innerHTML = col.innerHTML; + for (e in col.events) + domcell['on' + e] = col.events[e]; domrow.appendChild(domcell); } @@ -326,18 +397,22 @@ var row = this.rows[id]; if (!row) return false; - var domrow = row.obj; - for (var domcell, col, i=0; cols && i < cols.length; i++) { + var i, domrow = row.obj; + for (i = 0; cols && i < cols.length; i++) { this.get_cell(domrow, i).html(cols[i]); } if (newid) { delete this.rows[id]; + domrow.uid = newid; domrow.id = 'rcmrow' + newid; this.init_row(domrow); if (select) this.selection[0] = newid; + + if (this.last_selected == id) + this.last_selected = newid; } }, @@ -347,39 +422,80 @@ */ focus: function(e) { - var n, id; + if (this.focused) + return; + this.focused = true; - for (n in this.selection) { - id = this.selection[n]; - if (this.rows[id] && this.rows[id].obj) { - $(this.rows[id].obj).addClass('selected').removeClass('unfocused'); - } + if (e) + rcube_event.cancel(e); + + var focus_elem = null; + + if (this.last_selected && this.rows[this.last_selected]) { + focus_elem = $(this.rows[this.last_selected].obj).find(this.col_tagname()).eq(this.subject_col).attr('tabindex', '0'); } // Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620) - // It looks that window.focus() does the job for all browsers, but not Firefox (#1489058) - $(':focus:not(body)').blur(); - window.focus(); + if (focus_elem && focus_elem.length) { + // We now fix this by explicitly assigning focus to a dedicated link element + this.focus_noscroll(focus_elem); + } + else { + // It looks that window.focus() does the job for all browsers, but not Firefox (#1489058) + $('iframe,:focus:not(body)').blur(); + window.focus(); + } - if (e || (e = window.event)) - rcube_event.cancel(e); + $(this.list).addClass('focus').removeAttr('tabindex'); + + // set internal focus pointer to first row + if (!this.last_selected) + this.select_first(CONTROL_KEY); }, /** * remove focus from the list */ -blur: function() +blur: function(e) { - var n, id; this.focused = false; - for (n in this.selection) { - id = this.selection[n]; - if (this.rows[id] && this.rows[id].obj) { - $(this.rows[id].obj).removeClass('selected focused').addClass('unfocused'); - } + + // avoid the table getting focus right again + var me = this; + setTimeout(function(){ + $(me.list).removeClass('focus').attr('tabindex', '0'); + }, 20); + + if (this.last_selected && this.rows[this.last_selected]) { + $(this.rows[this.last_selected].obj) + .find(this.col_tagname()).eq(this.subject_col).removeAttr('tabindex'); } +}, + +/** + * Focus the given element without scrolling the list container + */ +focus_noscroll: function(elem) +{ + var y = this.frame.scrollTop || this.frame.scrollY; + elem.focus(); + this.frame.scrollTop = y; +}, + + +/** + * Set/unset the given column as hidden + */ +hide_column: function(col, hide) +{ + var method = hide ? 'addClass' : 'removeClass'; + + if (this.fixed_header) + $(this.row_tagname()+' '+this.col_tagname()+'.'+col, this.fixed_header)[method]('hidden'); + + $(this.row_tagname()+' '+this.col_tagname()+'.'+col, this.list)[method]('hidden'); }, @@ -456,6 +572,10 @@ */ click_row: function(e, id) { + // sanity check + if (!id || !this.rows[id]) + return false; + // don't do anything (another action processed before) if (!this.is_event_target(e)) return true; @@ -485,6 +605,8 @@ } this.rows[id].clicked = now; + this.focus(); + return false; }, @@ -577,7 +699,7 @@ row.expanded = true; depth = row.depth; new_row = row.obj.nextSibling; - this.update_expando(row.uid, true); + this.update_expando(row.id, true); this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); } else { @@ -627,7 +749,7 @@ row.expanded = false; depth = row.depth; new_row = row.obj.nextSibling; - this.update_expando(row.uid); + this.update_expando(row.id); this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); // don't collapse sub-root tree in multiexpand mode @@ -649,7 +771,7 @@ $(new_row).css('display', 'none'); if (r.has_children && r.expanded) { r.expanded = false; - this.update_expando(r.uid, false); + this.update_expando(r.id, false); this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); } } @@ -671,7 +793,7 @@ row.expanded = true; depth = row.depth; new_row = row.obj.nextSibling; - this.update_expando(row.uid, true); + this.update_expando(row.id, true); this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); } else { @@ -688,7 +810,7 @@ $(new_row).css('display', ''); if (r.has_children && !r.expanded) { r.expanded = true; - this.update_expando(r.uid, true); + this.update_expando(r.id, true); this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); } } @@ -702,13 +824,28 @@ }, -update_expando: function(uid, expanded) +update_expando: function(id, expanded) { - var expando = document.getElementById('rcmexpando' + uid); + var expando = document.getElementById('rcmexpando' + id); if (expando) expando.className = expanded ? 'expanded' : 'collapsed'; }, +get_row_uid: function(row) +{ + if (!row) + return; + + if (!row.uid) { + var uid = $(row).data('uid'); + if (uid) + row.uid = uid; + else if (String(row.id).match(this.id_regexp)) + row.uid = RegExp.$1; + } + + return row.uid; +}, /** * get first/next/previous/last rows that are not hidden @@ -744,11 +881,11 @@ get_first_row: function() { if (this.rowcount) { - var i, len, rows = this.tbody.childNodes; + var i, uid, rows = this.tbody.childNodes; - for (i=0, len=rows.length-1; i<len; i++) - if (rows[i].id && String(rows[i].id).match(this.id_regexp) && this.rows[RegExp.$1] != null) - return RegExp.$1; + for (i=0; i<rows.length; i++) + if (rows[i].id && (uid = this.get_row_uid(rows[i]))) + return uid; } return null; @@ -757,11 +894,11 @@ get_last_row: function() { if (this.rowcount) { - var i, rows = this.tbody.childNodes; + var i, uid, rows = this.tbody.childNodes; for (i=rows.length-1; i>=0; i--) - if (rows[i].id && String(rows[i].id).match(this.id_regexp) && this.rows[RegExp.$1] != null) - return RegExp.$1; + if (rows[i].id && (uid = this.get_row_uid(rows[i]))) + return uid; } return null; @@ -789,9 +926,10 @@ */ select_row: function(id, mod_key, with_mouse) { - var select_before = this.selection.join(','); + var select_before = this.selection.join(','), + in_selection_before = this.in_selection(id); - if (!this.multiselect) + if (!this.multiselect && with_mouse) mod_key = 0; if (!this.shift_start) @@ -827,20 +965,26 @@ this.multi_selecting = true; } - // trigger event if selection changed - if (this.selection.join(',') != select_before) - this.triggerEvent('select'); - - if (this.last_selected != 0 && this.rows[this.last_selected]) - $(this.rows[this.last_selected].obj).removeClass('focused'); + if (this.last_selected && this.rows[this.last_selected]) { + $(this.rows[this.last_selected].obj).removeClass('focused') + .find(this.col_tagname()).eq(this.subject_col).removeAttr('tabindex'); + } // unselect if toggleselect is active and the same row was clicked again - if (this.toggleselect && this.last_selected == id) { + if (this.toggleselect && in_selection_before && !mod_key) { this.clear_selection(); - id = null; } - else + // trigger event if selection changed + else if (this.selection.join(',') != select_before) { + this.triggerEvent('select'); + } + + if (this.rows[id]) { $(this.rows[id].obj).addClass('focused'); + // set cursor focus to link inside selected row + if (this.focused) + this.focus_noscroll($(this.rows[id].obj).find(this.col_tagname()).eq(this.subject_col).attr('tabindex', '0')); + } if (!this.selection.length) this.shift_start = null; @@ -960,11 +1104,11 @@ /** * Check if given id is part of the current selection */ -in_selection: function(id) +in_selection: function(id, index) { for (var n in this.selection) if (this.selection[n] == id) - return true; + return index ? parseInt(n) : true; return false; }, @@ -988,7 +1132,7 @@ this.highlight_row(n, true, true); } else { - $(this.rows[n].obj).removeClass('selected').removeClass('unfocused'); + $(this.rows[n].obj).removeClass('selected').removeAttr('aria-selected'); } } @@ -1029,7 +1173,7 @@ /** * Unselect selected row(s) */ -clear_selection: function(id) +clear_selection: function(id, no_event) { var n, num_select = this.selection.length; @@ -1045,14 +1189,16 @@ else { for (n in this.selection) if (this.rows[this.selection[n]]) { - $(this.rows[this.selection[n]].obj).removeClass('selected').removeClass('unfocused'); + $(this.rows[this.selection[n]].obj).removeClass('selected').removeAttr('aria-selected'); } this.selection = []; } - if (num_select && !this.selection.length) + if (num_select && !this.selection.length && !no_event) { this.triggerEvent('select'); + this.last_selected = null; + } }, @@ -1067,7 +1213,7 @@ if (deep !== false && res.length) { for (var uid, uids, i=0, len=res.length; i<len; i++) { uid = res[i]; - if (this.rows[uid].has_children && !this.rows[uid].expanded) { + if (this.rows[uid] && this.rows[uid].has_children && !this.rows[uid].expanded) { uids = this.row_children(uid); for (var j=0, uids_len=uids.length; j<uids_len; j++) { uid = uids[j]; @@ -1104,25 +1250,26 @@ if (!multiple) { if (this.selection.length > 1 || !this.in_selection(id)) { - this.clear_selection(); + this.clear_selection(null, true); this.selection[0] = id; - $(this.rows[id].obj).addClass('selected'); + $(this.rows[id].obj).addClass('selected').attr('aria-selected', 'true'); } } else { - if (!this.in_selection(id)) { // select row + var pre, post, p = this.in_selection(id, true); + + if (p === false) { // select row this.selection.push(id); - $(this.rows[id].obj).addClass('selected'); + $(this.rows[id].obj).addClass('selected').attr('aria-selected', 'true'); if (!norecur && !this.rows[id].expanded) this.highlight_children(id, true); } else { // unselect row - var p = $.inArray(id, this.selection), - a_pre = this.selection.slice(0, p), - a_post = this.selection.slice(p+1, this.selection.length); + pre = this.selection.slice(0, p); + post = this.selection.slice(p+1, this.selection.length); - this.selection = a_pre.concat(a_post); - $(this.rows[id].obj).removeClass('selected').removeClass('unfocused'); + this.selection = pre.concat(post); + $(this.rows[id].obj).removeClass('selected').removeAttr('aria-selected'); if (!norecur && !this.rows[id].expanded) this.highlight_children(id, false); } @@ -1152,6 +1299,7 @@ key_press: function(e) { var target = e.target || {}; + if (this.focused != true || target.nodeName == 'INPUT' || target.nodeName == 'TEXTAREA' || target.nodeName == 'SELECT') return true; @@ -1173,11 +1321,9 @@ case 37: // Left arrow key case 39: // Right arrow key - case 107: // Plus sign on a numeric keypad - case 109: // Minus sign on a numeric keypad // Stop propagation rcube_event.cancel(e); - var ret = this.use_plusminus_key(keyCode, mod_key); + var ret = this.use_arrow_key(keyCode, mod_key); this.key_pressed = keyCode; this.modkey = mod_key; this.triggerEvent('keypress'); @@ -1203,6 +1349,14 @@ return rcube_event.cancel(e); + case 9: // Tab + this.blur(); + break; + + case 13: // Enter + if (!this.selection.length) + this.select_row(this.last_selected, mod_key, false); + default: this.key_pressed = keyCode; this.modkey = mod_key; @@ -1222,55 +1376,57 @@ */ use_arrow_key: function(keyCode, mod_key) { - var new_row; + var new_row, + selected_row = this.rows[this.last_selected]; + // Safari uses the nonstandard keycodes 63232/63233 for up/down, if we're // using the keypress event (but not the keydown or keyup event). if (keyCode == 40 || keyCode == 63233) // down arrow key pressed new_row = this.get_next_row(); else if (keyCode == 38 || keyCode == 63232) // up arrow key pressed new_row = this.get_prev_row(); + else { + if (!selected_row || !selected_row.has_children) + return; + + // expand + if (keyCode == 39) { + if (selected_row.expanded) + return; + + if (mod_key == CONTROL_KEY || this.multiexpand) + this.expand_all(selected_row); + else + this.expand(selected_row); + } + // collapse + else { + if (!selected_row.expanded) + return; + + if (mod_key == CONTROL_KEY || this.multiexpand) + this.collapse_all(selected_row); + else + this.collapse(selected_row); + } + + this.update_expando(selected_row.id, selected_row.expanded); + + return false; + } if (new_row) { + // simulate ctr-key if no rows are selected + if (!mod_key && !this.selection.length) + mod_key = CONTROL_KEY; + this.select_row(new_row.uid, mod_key, false); this.scrollto(new_row.uid); } - - return false; -}, - - -/** - * Special handling method for +/- keys - */ -use_plusminus_key: function(keyCode, mod_key) -{ - var selected_row = this.rows[this.last_selected]; - - if (!selected_row || !selected_row.has_children) - return; - - // expand - if (keyCode == 39 || keyCode == 107) { - if (selected_row.expanded) - return; - - if (mod_key == CONTROL_KEY || this.multiexpand) - this.expand_all(selected_row); - else - this.expand(selected_row); + else if (!new_row && !selected_row) { + // select the first row if none selected yet + this.select_first(CONTROL_KEY); } - // collapse - else { - if (!selected_row.expanded) - return; - - if (mod_key == CONTROL_KEY || this.multiexpand) - this.collapse_all(selected_row); - else - this.collapse(selected_row); - } - - this.update_expando(selected_row.uid, selected_row.expanded); return false; }, @@ -1281,7 +1437,8 @@ */ scrollto: function(id) { - var row = this.rows[id].obj; + var row = this.rows[id] ? this.rows[id].obj : null; + if (row && this.frame) { var scroll_to = Number(row.offsetTop), head_offset = 0; @@ -1341,12 +1498,9 @@ // get selected rows (in display order), don't use this.selection here $(this.row_tagname() + '.selected', this.tbody).each(function() { - if (!String(this.id).match(self.id_regexp)) - return; + var uid = self.get_row_uid(this), row = self.rows[uid]; - var uid = RegExp.$1, row = self.rows[uid]; - - if ($.inArray(uid, selection) > -1) + if (!row || $.inArray(uid, selection) > -1) return; selection.push(uid); @@ -1373,7 +1527,11 @@ $('> ' + self.col_tagname(), self.rows[uid].obj).each(function(n, cell) { if (self.subject_col < 0 || (self.subject_col >= 0 && self.subject_col == n)) { - var subject = $(cell).text(); + // remove elements marked with "skip-on-drag" class + cell = $(cell).clone(); + $(cell).find('.skip-on-drag').remove(); + + var subject = cell.text(); if (subject) { // remove leading spaces @@ -1461,6 +1619,9 @@ var lpos = $(this.list).offset(), cells = this.thead.rows[0].cells; + // fix layer position when list is scrolled + lpos.top += this.list.scrollTop + this.list.parentNode.scrollTop; + // create dragging layer this.col_draglayer = $('<div>').attr('id', 'rcmcoldraglayer') .css(lpos).css({ position:'absolute', 'z-index':2001, @@ -1527,32 +1688,33 @@ this.col_draglayer = null; } - if (this.col_drag_active) - this.focus(); - this.col_drag_active = false; - rcube_event.remove_listener({event:'mousemove', object:this, method:'column_drag_mouse_move'}); rcube_event.remove_listener({event:'mouseup', object:this, method:'column_drag_mouse_up'}); + // remove temp divs this.del_dragfix(); - if (this.selected_column !== null && this.cols && this.cols.length) { - var i, cpos = 0, pos = rcube_event.get_mouse_pos(e); + if (this.col_drag_active) { + this.col_drag_active = false; + this.focus(); + this.triggerEvent('column_dragend', e); - // find destination position - for (i=0; i<this.cols.length; i++) { - if (pos.x >= this.cols[i]/2 + this.list_pos + cpos) - cpos += this.cols[i]; - else - break; - } + if (this.selected_column !== null && this.cols && this.cols.length) { + var i, cpos = 0, pos = rcube_event.get_mouse_pos(e); - if (i != this.selected_column && i != this.selected_column+1) { - this.column_replace(this.selected_column, i); + // find destination position + for (i=0; i<this.cols.length; i++) { + if (pos.x >= this.cols[i]/2 + this.list_pos + cpos) + cpos += this.cols[i]; + else + break; + } + + if (i != this.selected_column && i != this.selected_column+1) { + this.column_replace(this.selected_column, i); + } } } - - this.triggerEvent('column_dragend', e); return rcube_event.cancel(e); }, @@ -1665,3 +1827,6 @@ rcube_list_widget.prototype.addEventListener = rcube_event_engine.prototype.addEventListener; rcube_list_widget.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener; rcube_list_widget.prototype.triggerEvent = rcube_event_engine.prototype.triggerEvent; + +// static +rcube_list_widget._instances = []; -- Gitblit v1.9.1