From 59478e06c25303a790a0840ab2ac30662c4ef781 Mon Sep 17 00:00:00 2001 From: Hugues Hiegel Date: Tue, 5 Aug 2014 16:46:22 +0200 Subject: c'est la merde.. --- program/js/list.js | 1607 +--------------------------------------------------- 1 file changed, 1 insertion(+), 1606 deletions(-) (limited to 'program/js/list.js') diff --git a/program/js/list.js b/program/js/list.js index c2ad3f7c3..fbb478db7 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -1,1606 +1 @@ -/* - +-----------------------------------------------------------------------+ - | 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 | - | Charles McNulty | - +-----------------------------------------------------------------------+ - | Requires: common.js | - +-----------------------------------------------------------------------+ -*/ - - -/** - * Roundcube List Widget class - * @contructor - */ -function rcube_list_widget(list, p) -{ - // static contants - this.ENTER_KEY = 13; - this.DELETE_KEY = 46; - this.BACKSPACE_KEY = 8; - - this.list = list ? list : null; - this.tagname = this.list ? this.list.nodeName.toLowerCase() : 'table'; - 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.modkey = 0; - this.multiselect = false; - this.multiexpand = false; - this.multi_selecting = false; - this.draggable = false; - this.column_movable = false; - this.keyboard = false; - this.toggleselect = false; - - this.dont_select = false; - this.drag_active = false; - this.col_drag_active = false; - this.column_fixed = null; - this.last_selected = 0; - this.shift_start = 0; - this.in_selection_before = false; - this.focused = false; - this.drag_mouse_start = null; - this.dblclick_time = 500; // default value on MS Windows is 500 - this.row_init = function(){}; // @deprecated; use list.addEventListener('initrow') instead - - // overwrite default paramaters - if (p && typeof p === 'object') - for (var n in p) - this[n] = p[n]; -}; - - -rcube_list_widget.prototype = { - - -/** - * get all message rows from HTML table and init each row - */ -init: function() -{ - if (this.tagname == 'table' && this.list && this.list.tBodies[0]) { - this.thead = this.list.tHead; - this.tbody = this.list.tBodies[0]; - } - else if (this.tagname != 'table' && this.list) { - this.tbody = this.list; - } - - if (this.tbody) { - this.rows = []; - this.rowcount = 0; - - var r, len, rows = this.tbody.childNodes; - - for (r=0, len=rows.length; r= 0) { - this.init_fixed_header(); - } - - var col, r, p = this; - // add events for list columns moving - if (this.column_movable && this.thead && this.thead.rows) { - for (r=0; r') - .attr('class', this.list.className + ' fixedcopy') - .css({ position:'fixed' }) - .append(clone) - .append(''); - $(this.list).before(this.fixed_header); - - var me = this; - $(window).resize(function(){ me.resize() }); - } - else { - $(this.fixed_header).find('thead').replaceWith(clone); - } - - this.thead = clone.get(0); - this.resize(); -}, - -resize: function() -{ - if (!this.fixed_header) - return; - - var column_widths = []; - - // get column widths from original thead - $(this.tbody).parent().find('thead tr 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]); - }); -}, - -/** - * Remove all list rows - */ -clear: function(sel) -{ - if (this.tagname == 'table') { - var tbody = document.createElement('tbody'); - this.list.insertBefore(tbody, this.tbody); - this.list.removeChild(this.list.tBodies[1]); - this.tbody = tbody; - } - else { - $(this.row_tagname() + ':not(.thead)', this.tbody).remove(); - } - - this.rows = []; - this.rowcount = 0; - - if (sel) - this.clear_selection(); - - // reset scroll position (in Opera) - if (this.frame) - this.frame.scrollTop = 0; -}, - - -/** - * 'remove' message row from list (just hide it) - */ -remove_row: function(uid, sel_next) -{ - var node = this.rows[uid] ? this.rows[uid].obj : null; - - if (!node) - return; - - node.style.display = 'none'; - - if (sel_next) - this.select_next(); - - delete this.rows[uid]; - this.rowcount--; -}, - - -/** - * Add row to the list and initialize it - */ -insert_row: function(row, before) -{ - var tbody = this.tbody; - - // create a real dom node first - 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.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++) { - col = row.cols[i]; - domcell = document.createElement(this.col_tagname()); - if (col.className) domcell.className = col.className; - if (col.innerHTML) domcell.innerHTML = col.innerHTML; - domrow.appendChild(domcell); - } - - row = domrow; - } - - if (before && tbody.childNodes.length) - tbody.insertBefore(row, (typeof before == 'object' && before.parentNode == tbody) ? before : tbody.firstChild); - else - tbody.appendChild(row); - - this.init_row(row); - this.rowcount++; -}, - -/** - * - */ -update_row: function(id, cols, newid, select) -{ - var row = this.rows[id]; - if (!row) return false; - - var domrow = row.obj; - for (var domcell, col, i=0; cols && i < cols.length; i++) { - this.get_cell(domrow, i).html(cols[i]); - } - - if (newid) { - delete this.rows[id]; - domrow.id = 'rcmrow' + newid; - this.init_row(domrow); - - if (select) - this.selection[0] = newid; - } -}, - - -/** - * Set focus to the list - */ -focus: function(e) -{ - var n, id; - 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'); - } - } - - // 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 (e || (e = window.event)) - rcube_event.cancel(e); -}, - - -/** - * remove focus from the list - */ -blur: function() -{ - 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'); - } - } -}, - - -/** - * onmousedown-handler of message list column - */ -drag_column: function(e, col) -{ - if (this.colcount > 1) { - this.drag_start = true; - this.drag_mouse_start = rcube_event.get_mouse_pos(e); - - rcube_event.add_listener({event:'mousemove', object:this, method:'column_drag_mouse_move'}); - rcube_event.add_listener({event:'mouseup', object:this, method:'column_drag_mouse_up'}); - - // enable dragging over iframes - this.add_dragfix(); - - // find selected column number - for (var i=0; i= p.depth - 1) { - last_expanded_parent_depth = p.depth; - $(new_row).css('display', ''); - r.expanded = true; - this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); - } - } - else - if (row && (! p || p.depth <= depth)) - break; - } - } - } - new_row = new_row.nextSibling; - } - - this.resize(); - this.triggerEvent('listupdate'); - return false; -}, - - -collapse_all: function(row) -{ - var depth, new_row, r; - - if (row) { - row.expanded = false; - depth = row.depth; - new_row = row.obj.nextSibling; - this.update_expando(row.uid); - this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); - - // don't collapse sub-root tree in multiexpand mode - if (depth && this.multiexpand) - return false; - } - else { - new_row = this.tbody.firstChild; - depth = 0; - } - - while (new_row) { - if (new_row.nodeType == 1) { - if (r = this.rows[new_row.uid]) { - if (row && (!r.depth || r.depth <= depth)) - break; - - if (row || r.depth) - $(new_row).css('display', 'none'); - if (r.has_children && r.expanded) { - r.expanded = false; - this.update_expando(r.uid, false); - this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); - } - } - } - new_row = new_row.nextSibling; - } - - this.resize(); - this.triggerEvent('listupdate'); - return false; -}, - - -expand_all: function(row) -{ - var depth, new_row, r; - - if (row) { - row.expanded = true; - depth = row.depth; - new_row = row.obj.nextSibling; - this.update_expando(row.uid, true); - this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); - } - else { - new_row = this.tbody.firstChild; - depth = 0; - } - - while (new_row) { - if (new_row.nodeType == 1) { - if (r = this.rows[new_row.uid]) { - if (row && r.depth <= depth) - break; - - $(new_row).css('display', ''); - if (r.has_children && !r.expanded) { - r.expanded = true; - this.update_expando(r.uid, true); - this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); - } - } - } - new_row = new_row.nextSibling; - } - - this.resize(); - this.triggerEvent('listupdate'); - return false; -}, - - -update_expando: function(uid, expanded) -{ - var expando = document.getElementById('rcmexpando' + uid); - if (expando) - expando.className = expanded ? 'expanded' : 'collapsed'; -}, - - -/** - * get first/next/previous/last rows that are not hidden - */ -get_next_row: function() -{ - if (!this.rows) - return false; - - var last_selected_row = this.rows[this.last_selected], - new_row = last_selected_row ? last_selected_row.obj.nextSibling : null; - - while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) - new_row = new_row.nextSibling; - - return new_row; -}, - -get_prev_row: function() -{ - if (!this.rows) - return false; - - var last_selected_row = this.rows[this.last_selected], - new_row = last_selected_row ? last_selected_row.obj.previousSibling : null; - - while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) - new_row = new_row.previousSibling; - - return new_row; -}, - -get_first_row: function() -{ - if (this.rowcount) { - var i, len, rows = this.tbody.childNodes; - - for (i=0, len=rows.length-1; i=0; i--) - if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) - return RegExp.$1; - } - - return null; -}, - -row_tagname: function() -{ - var row_tagnames = { table:'tr', ul:'li', '*':'div' }; - return row_tagnames[this.tagname] || row_tagnames['*']; -}, - -col_tagname: function() -{ - var col_tagnames = { table:'td', '*':'span' }; - return col_tagnames[this.tagname] || col_tagnames['*']; -}, - -get_cell: function(row, index) -{ - return $(this.col_tagname(), row).eq(index); -}, - -/** - * selects or unselects the proper row depending on the modifier key pressed - */ -select_row: function(id, mod_key, with_mouse) -{ - var select_before = this.selection.join(','); - if (!this.multiselect) - mod_key = 0; - - if (!this.shift_start) - this.shift_start = id - - if (!mod_key) { - this.shift_start = id; - this.highlight_row(id, false); - this.multi_selecting = false; - } - else { - switch (mod_key) { - case SHIFT_KEY: - this.shift_select(id, false); - break; - - case CONTROL_KEY: - if (!with_mouse) - this.highlight_row(id, true); - break; - - case CONTROL_SHIFT_KEY: - this.shift_select(id, true); - break; - - default: - this.highlight_row(id, false); - break; - } - 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'); - - // unselect if toggleselect is active and the same row was clicked again - if (this.toggleselect && this.last_selected == id) { - this.clear_selection(); - id = null; - } - else - $(this.rows[id].obj).addClass('focused'); - - if (!this.selection.length) - this.shift_start = null; - - this.last_selected = id; -}, - - -/** - * Alias method for select_row - */ -select: function(id) -{ - this.select_row(id, false); - this.scrollto(id); -}, - - -/** - * Select row next to the last selected one. - * Either below or above. - */ -select_next: function() -{ - var next_row = this.get_next_row(), - prev_row = this.get_prev_row(), - new_row = (next_row) ? next_row : prev_row; - - if (new_row) - this.select_row(new_row.uid, false, false); -}, - - -/** - * Select first row - */ -select_first: function(mod_key) -{ - var row = this.get_first_row(); - if (row) { - if (mod_key) { - this.shift_select(row, mod_key); - this.triggerEvent('select'); - this.scrollto(row); - } - else { - this.select(row); - } - } -}, - - -/** - * Select last row - */ -select_last: function(mod_key) -{ - var row = this.get_last_row(); - if (row) { - if (mod_key) { - this.shift_select(row, mod_key); - this.triggerEvent('select'); - this.scrollto(row); - } - else { - this.select(row); - } - } -}, - - -/** - * Add all childs of the given row to selection - */ -select_children: function(uid) -{ - var i, children = this.row_children(uid), len = children.length; - - for (i=0; i to_rowIndex) ? from_rowIndex : to_rowIndex); - - // iterate through the entire message list - for (n in this.rows) { - if (this._rowIndex(this.rows[n].obj) >= i && this._rowIndex(this.rows[n].obj) <= j) { - if (!this.in_selection(n)) { - this.highlight_row(n, true); - } - } - else { - if (this.in_selection(n) && !control) { - this.highlight_row(n, true); - } - } - } -}, - -/** - * Helper method to emulate the rowIndex property of non-tr elements - */ -_rowIndex: function(obj) -{ - return (obj.rowIndex !== undefined) ? obj.rowIndex : $(obj).prevAll().length; -}, - -/** - * Check if given id is part of the current selection - */ -in_selection: function(id) -{ - for (var n in this.selection) - if (this.selection[n]==id) - return true; - - return false; -}, - - -/** - * Select each row in list - */ -select_all: function(filter) -{ - if (!this.rows || !this.rows.length) - return false; - - // reset but remember selection first - var n, select_before = this.selection.join(','); - this.selection = []; - - for (n in this.rows) { - if (!filter || this.rows[n][filter] == true) { - this.last_selected = n; - this.highlight_row(n, true, true); - } - else { - $(this.rows[n].obj).removeClass('selected').removeClass('unfocused'); - } - } - - // trigger event if selection changed - if (this.selection.join(',') != select_before) - this.triggerEvent('select'); - - this.focus(); - - return true; -}, - - -/** - * Invert selection - */ -invert_selection: function() -{ - if (!this.rows || !this.rows.length) - return false; - - // remember old selection - var n, select_before = this.selection.join(','); - - for (n in this.rows) - this.highlight_row(n, true); - - // trigger event if selection changed - if (this.selection.join(',') != select_before) - this.triggerEvent('select'); - - this.focus(); - - return true; -}, - - -/** - * Unselect selected row(s) - */ -clear_selection: function(id) -{ - var n, num_select = this.selection.length; - - // one row - if (id) { - for (n in this.selection) - if (this.selection[n] == id) { - this.selection.splice(n,1); - break; - } - } - // all rows - else { - for (n in this.selection) - if (this.rows[this.selection[n]]) { - $(this.rows[this.selection[n]].obj).removeClass('selected').removeClass('unfocused'); - } - - this.selection = []; - } - - if (num_select && !this.selection.length) - this.triggerEvent('select'); -}, - - -/** - * Getter for the selection array - */ -get_selection: function() -{ - return this.selection; -}, - - -/** - * Return the ID if only one row is selected - */ -get_single_selection: function() -{ - if (this.selection.length == 1) - return this.selection[0]; - else - return null; -}, - - -/** - * Highlight/unhighlight a row - */ -highlight_row: function(id, multiple, norecur) -{ - if (!this.rows[id]) - return; - - if (!multiple) { - if (this.selection.length > 1 || !this.in_selection(id)) { - this.clear_selection(); - this.selection[0] = id; - $(this.rows[id].obj).addClass('selected'); - } - } - else { - if (!this.in_selection(id)) { // select row - this.selection.push(id); - $(this.rows[id].obj).addClass('selected'); - 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); - - this.selection = a_pre.concat(a_post); - $(this.rows[id].obj).removeClass('selected').removeClass('unfocused'); - if (!norecur && !this.rows[id].expanded) - this.highlight_children(id, false); - } - } -}, - - -/** - * Highlight/unhighlight all childs of the given row - */ -highlight_children: function(id, status) -{ - var i, selected, - children = this.row_children(id), len = children.length; - - for (i=0; i