Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F3310969
list.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
36 KB
Referenced Files
None
Subscribers
None
list.js
View Options
/*
+-----------------------------------------------------------------------+
| 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 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
.
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
<
len
;
r
++
)
{
this
.
init_row
(
rows
[
r
]);
this
.
rowcount
++
;
}
this
.
init_header
();
this
.
frame
=
this
.
list
.
parentNode
;
// set body events
if
(
this
.
keyboard
)
rcube_event
.
add_listener
({
event
:
'keydown'
,
object
:
this
,
method
:
'key_press'
});
}
},
/**
* Init list row and set mouse events on it
*/
init_row
:
function
(
row
)
{
// make references in internal array and set event handlers
if
(
row
&&
String
(
row
.
id
).
match
(
/^rcmrow([a-z0-9\-_=\+\/]+)/i
))
{
var
self
=
this
,
uid
=
RegExp
.
$1
;
row
.
uid
=
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
);
};
if
(
bw
.
mobile
)
{
row
.
addEventListener
(
'touchstart'
,
function
(
e
)
{
if
(
e
.
touches
.
length
==
1
)
{
if
(
!
self
.
drag_row
(
rcube_event
.
touchevent
(
e
.
touches
[
0
]),
this
.
uid
))
e
.
preventDefault
();
}
},
false
);
row
.
addEventListener
(
'touchend'
,
function
(
e
)
{
if
(
e
.
changedTouches
.
length
==
1
)
if
(
!
self
.
click_row
(
rcube_event
.
touchevent
(
e
.
changedTouches
[
0
]),
this
.
uid
))
e
.
preventDefault
();
},
false
);
}
if
(
document
.
all
)
row
.
onselectstart
=
function
()
{
return
false
;
};
this
.
row_init
(
this
.
rows
[
uid
]);
// legacy support
this
.
triggerEvent
(
'initrow'
,
this
.
rows
[
uid
]);
}
},
/**
* Init list column headers and set mouse events on them
*/
init_header
:
function
()
{
if
(
this
.
thead
)
{
this
.
colcount
=
0
;
var
col
,
r
,
p
=
this
;
// add events for list columns moving
if
(
this
.
column_movable
&&
this
.
thead
&&
this
.
thead
.
rows
)
{
for
(
r
=
0
;
r
<
this
.
thead
.
rows
[
0
].
cells
.
length
;
r
++
)
{
if
(
this
.
column_fixed
==
r
)
continue
;
col
=
this
.
thead
.
rows
[
0
].
cells
[
r
];
col
.
onmousedown
=
function
(
e
){
return
p
.
drag_column
(
e
,
this
);
};
this
.
colcount
++
;
}
}
}
},
/**
* 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
<
this
.
thead
.
rows
[
0
].
cells
.
length
;
i
++
)
{
if
(
col
==
this
.
thead
.
rows
[
0
].
cells
[
i
])
{
this
.
selected_column
=
i
;
break
;
}
}
}
return
false
;
},
/**
* onmousedown-handler of message list row
*/
drag_row
:
function
(
e
,
id
)
{
// don't do anything (another action processed before)
var
evtarget
=
rcube_event
.
get_target
(
e
),
tagname
=
evtarget
.
tagName
.
toLowerCase
();
if
(
this
.
dont_select
||
(
evtarget
&&
(
tagname
==
'input'
||
tagname
==
'img'
)))
return
true
;
// accept right-clicks
if
(
rcube_event
.
get_button
(
e
)
==
2
)
return
true
;
this
.
in_selection_before
=
this
.
in_selection
(
id
)
?
id
:
false
;
// selects currently unselected row
if
(
!
this
.
in_selection_before
)
{
var
mod_key
=
rcube_event
.
get_modifier
(
e
);
this
.
select_row
(
id
,
mod_key
,
false
);
}
if
(
this
.
draggable
&&
this
.
selection
.
length
)
{
this
.
drag_start
=
true
;
this
.
drag_mouse_start
=
rcube_event
.
get_mouse_pos
(
e
);
rcube_event
.
add_listener
({
event
:
'mousemove'
,
object
:
this
,
method
:
'drag_mouse_move'
});
rcube_event
.
add_listener
({
event
:
'mouseup'
,
object
:
this
,
method
:
'drag_mouse_up'
});
if
(
bw
.
mobile
)
{
rcube_event
.
add_listener
({
event
:
'touchmove'
,
object
:
this
,
method
:
'drag_mouse_move'
});
rcube_event
.
add_listener
({
event
:
'touchend'
,
object
:
this
,
method
:
'drag_mouse_up'
});
}
// enable dragging over iframes
this
.
add_dragfix
();
}
return
false
;
},
/**
* onmouseup-handler of message list row
*/
click_row
:
function
(
e
,
id
)
{
var
now
=
new
Date
().
getTime
(),
mod_key
=
rcube_event
.
get_modifier
(
e
),
evtarget
=
rcube_event
.
get_target
(
e
),
tagname
=
evtarget
.
tagName
.
toLowerCase
();
if
((
evtarget
&&
(
tagname
==
'input'
||
tagname
==
'img'
)))
return
true
;
// don't do anything (another action processed before)
if
(
this
.
dont_select
)
{
this
.
dont_select
=
false
;
return
false
;
}
var
dblclicked
=
now
-
this
.
rows
[
id
].
clicked
<
this
.
dblclick_time
;
// unselects currently selected row
if
(
!
this
.
drag_active
&&
this
.
in_selection_before
==
id
&&
!
dblclicked
)
this
.
select_row
(
id
,
mod_key
,
false
);
this
.
drag_start
=
false
;
this
.
in_selection_before
=
false
;
// row was double clicked
if
(
this
.
rows
&&
dblclicked
&&
this
.
in_selection
(
id
))
{
this
.
triggerEvent
(
'dblclick'
);
now
=
0
;
}
else
this
.
triggerEvent
(
'click'
);
if
(
!
this
.
drag_active
)
{
// remove temp divs
this
.
del_dragfix
();
rcube_event
.
cancel
(
e
);
}
this
.
rows
[
id
].
clicked
=
now
;
return
false
;
},
/*
* Returns thread root ID for specified row ID
*/
find_root
:
function
(
uid
)
{
var
r
=
this
.
rows
[
uid
];
if
(
r
&&
r
.
parent_uid
)
return
this
.
find_root
(
r
.
parent_uid
);
else
return
uid
;
},
expand_row
:
function
(
e
,
id
)
{
var
row
=
this
.
rows
[
id
],
evtarget
=
rcube_event
.
get_target
(
e
),
mod_key
=
rcube_event
.
get_modifier
(
e
);
// Don't select this message
this
.
dont_select
=
true
;
// Don't treat double click on the expando as double click on the message.
row
.
clicked
=
0
;
if
(
row
.
expanded
)
{
evtarget
.
className
=
'collapsed'
;
if
(
mod_key
==
CONTROL_KEY
||
this
.
multiexpand
)
this
.
collapse_all
(
row
);
else
this
.
collapse
(
row
);
}
else
{
evtarget
.
className
=
'expanded'
;
if
(
mod_key
==
CONTROL_KEY
||
this
.
multiexpand
)
this
.
expand_all
(
row
);
else
this
.
expand
(
row
);
}
},
collapse
:
function
(
row
)
{
row
.
expanded
=
false
;
this
.
triggerEvent
(
'expandcollapse'
,
{
uid
:
row
.
uid
,
expanded
:
row
.
expanded
,
obj
:
row
.
obj
});
var
depth
=
row
.
depth
;
var
new_row
=
row
?
row
.
obj
.
nextSibling
:
null
;
var
r
;
while
(
new_row
)
{
if
(
new_row
.
nodeType
==
1
)
{
var
r
=
this
.
rows
[
new_row
.
uid
];
if
(
r
&&
r
.
depth
<=
depth
)
break
;
$
(
new_row
).
css
(
'display'
,
'none'
);
if
(
r
.
expanded
)
{
r
.
expanded
=
false
;
this
.
triggerEvent
(
'expandcollapse'
,
{
uid
:
r
.
uid
,
expanded
:
r
.
expanded
,
obj
:
new_row
});
}
}
new_row
=
new_row
.
nextSibling
;
}
this
.
triggerEvent
(
'listupdate'
);
return
false
;
},
expand
:
function
(
row
)
{
var
r
,
p
,
depth
,
new_row
,
last_expanded_parent_depth
;
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
{
var
tbody
=
this
.
tbody
;
new_row
=
tbody
.
firstChild
;
depth
=
0
;
last_expanded_parent_depth
=
0
;
}
while
(
new_row
)
{
if
(
new_row
.
nodeType
==
1
)
{
r
=
this
.
rows
[
new_row
.
uid
];
if
(
r
)
{
if
(
row
&&
(
!
r
.
depth
||
r
.
depth
<=
depth
))
break
;
if
(
r
.
parent_uid
)
{
p
=
this
.
rows
[
r
.
parent_uid
];
if
(
p
&&
p
.
expanded
)
{
if
((
row
&&
p
==
row
)
||
last_expanded_parent_depth
>=
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
.
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
.
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
.
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
<
len
;
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
;
},
get_last_row
:
function
()
{
if
(
this
.
rowcount
)
{
var
i
,
rows
=
this
.
tbody
.
childNodes
;
for
(
i
=
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
<
len
;
i
++
)
if
(
!
this
.
in_selection
(
children
[
i
]))
this
.
select_row
(
children
[
i
],
CONTROL_KEY
);
},
/**
* Perform selection when shift key is pressed
*/
shift_select
:
function
(
id
,
control
)
{
if
(
!
this
.
rows
[
this
.
shift_start
]
||
!
this
.
selection
.
length
)
this
.
shift_start
=
id
;
var
n
,
i
,
j
,
to_row
=
this
.
rows
[
id
],
from_rowIndex
=
this
.
_rowIndex
(
this
.
rows
[
this
.
shift_start
].
obj
),
to_rowIndex
=
this
.
_rowIndex
(
to_row
.
obj
);
if
(
!
to_row
.
expanded
&&
to_row
.
has_children
)
if
(
to_row
=
this
.
rows
[(
this
.
row_children
(
id
)).
pop
()])
to_rowIndex
=
this
.
_rowIndex
(
to_row
.
obj
);
i
=
((
from_rowIndex
<
to_rowIndex
)
?
from_rowIndex
:
to_rowIndex
),
j
=
((
from_rowIndex
>
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
<
len
;
i
++
)
{
selected
=
this
.
in_selection
(
children
[
i
]);
if
((
status
&&
!
selected
)
||
(
!
status
&&
selected
))
this
.
highlight_row
(
children
[
i
],
true
,
true
);
}
},
/**
* Handler for keyboard events
*/
key_press
:
function
(
e
)
{
var
target
=
e
.
target
||
{};
if
(
this
.
focused
!=
true
||
target
.
nodeName
==
'INPUT'
||
target
.
nodeName
==
'TEXTAREA'
||
target
.
nodeName
==
'SELECT'
)
return
true
;
var
keyCode
=
rcube_event
.
get_keycode
(
e
),
mod_key
=
rcube_event
.
get_modifier
(
e
);
switch
(
keyCode
)
{
case
40
:
case
38
:
case
63233
:
// "down", in safari keypress
case
63232
:
// "up", in safari keypress
// Stop propagation so that the browser doesn't scroll
rcube_event
.
cancel
(
e
);
return
this
.
use_arrow_key
(
keyCode
,
mod_key
);
case
61
:
case
107
:
// Plus sign on a numeric keypad (fc11 + firefox 3.5.2)
case
109
:
case
32
:
// Stop propagation
rcube_event
.
cancel
(
e
);
var
ret
=
this
.
use_plusminus_key
(
keyCode
,
mod_key
);
this
.
key_pressed
=
keyCode
;
this
.
modkey
=
mod_key
;
this
.
triggerEvent
(
'keypress'
);
this
.
modkey
=
0
;
return
ret
;
case
36
:
// Home
this
.
select_first
(
mod_key
);
return
rcube_event
.
cancel
(
e
);
case
35
:
// End
this
.
select_last
(
mod_key
);
return
rcube_event
.
cancel
(
e
);
case
27
:
if
(
this
.
drag_active
)
return
this
.
drag_mouse_up
(
e
);
if
(
this
.
col_drag_active
)
{
this
.
selected_column
=
null
;
return
this
.
column_drag_mouse_up
(
e
);
}
return
rcube_event
.
cancel
(
e
);
default
:
this
.
key_pressed
=
keyCode
;
this
.
modkey
=
mod_key
;
this
.
triggerEvent
(
'keypress'
);
this
.
modkey
=
0
;
if
(
this
.
key_pressed
==
this
.
BACKSPACE_KEY
)
return
rcube_event
.
cancel
(
e
);
}
return
true
;
},
/**
* Special handling method for arrow keys
*/
use_arrow_key
:
function
(
keyCode
,
mod_key
)
{
var
new_row
;
// 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
();
if
(
new_row
)
{
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
)
return
;
if
(
keyCode
==
32
)
keyCode
=
selected_row
.
expanded
?
109
:
61
;
if
(
keyCode
==
61
||
keyCode
==
107
)
if
(
mod_key
==
CONTROL_KEY
||
this
.
multiexpand
)
this
.
expand_all
(
selected_row
);
else
this
.
expand
(
selected_row
);
else
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
;
},
/**
* Try to scroll the list to make the specified row visible
*/
scrollto
:
function
(
id
)
{
var
row
=
this
.
rows
[
id
].
obj
;
if
(
row
&&
this
.
frame
)
{
var
scroll_to
=
Number
(
row
.
offsetTop
);
// expand thread if target row is hidden (collapsed)
if
(
!
scroll_to
&&
this
.
rows
[
id
].
parent_uid
)
{
var
parent
=
this
.
find_root
(
this
.
rows
[
id
].
uid
);
this
.
expand_all
(
this
.
rows
[
parent
]);
scroll_to
=
Number
(
row
.
offsetTop
);
}
if
(
scroll_to
<
Number
(
this
.
frame
.
scrollTop
))
this
.
frame
.
scrollTop
=
scroll_to
;
else
if
(
scroll_to
+
Number
(
row
.
offsetHeight
)
>
Number
(
this
.
frame
.
scrollTop
)
+
Number
(
this
.
frame
.
offsetHeight
))
this
.
frame
.
scrollTop
=
(
scroll_to
+
Number
(
row
.
offsetHeight
))
-
Number
(
this
.
frame
.
offsetHeight
);
}
},
/**
* Handler for mouse move events
*/
drag_mouse_move
:
function
(
e
)
{
// convert touch event
if
(
e
.
type
==
'touchmove'
)
{
if
(
e
.
changedTouches
.
length
==
1
)
e
=
rcube_event
.
touchevent
(
e
.
changedTouches
[
0
]);
else
return
rcube_event
.
cancel
(
e
);
}
if
(
this
.
drag_start
)
{
// check mouse movement, of less than 3 pixels, don't start dragging
var
m
=
rcube_event
.
get_mouse_pos
(
e
);
if
(
!
this
.
drag_mouse_start
||
(
Math
.
abs
(
m
.
x
-
this
.
drag_mouse_start
.
x
)
<
3
&&
Math
.
abs
(
m
.
y
-
this
.
drag_mouse_start
.
y
)
<
3
))
return
false
;
if
(
!
this
.
draglayer
)
this
.
draglayer
=
$
(
'<div>'
).
attr
(
'id'
,
'rcmdraglayer'
)
.
css
({
position
:
'absolute'
,
display
:
'none'
,
'z-index'
:
2000
})
.
appendTo
(
document
.
body
);
// also select childs of (collapsed) threads for dragging
var
n
,
uid
,
selection
=
$
.
merge
([],
this
.
selection
);
for
(
n
in
selection
)
{
uid
=
selection
[
n
];
if
(
!
this
.
rows
[
uid
].
expanded
)
this
.
select_children
(
uid
);
}
// reset content
this
.
draglayer
.
html
(
''
);
// get subjects of selected messages
var
i
,
n
,
obj
,
me
;
for
(
n
=
0
;
n
<
this
.
selection
.
length
;
n
++
)
{
// only show 12 lines
if
(
n
>
12
)
{
this
.
draglayer
.
append
(
'...'
);
break
;
}
me
=
this
;
if
(
obj
=
this
.
rows
[
this
.
selection
[
n
]].
obj
)
{
$
(
'> '
+
this
.
col_tagname
(),
obj
).
each
(
function
(
i
,
elem
){
if
(
n
==
0
)
me
.
drag_start_pos
=
$
(
elem
).
offset
();
if
(
me
.
subject_col
<
0
||
(
me
.
subject_col
>=
0
&&
me
.
subject_col
==
i
))
{
var
subject
=
$
(
elem
).
text
();
if
(
subject
)
{
// remove leading spaces
subject
=
$
.
trim
(
subject
);
// truncate line to 50 characters
subject
=
(
subject
.
length
>
50
?
subject
.
substring
(
0
,
50
)
+
'...'
:
subject
);
var
entry
=
$
(
'<div>'
).
text
(
subject
);
me
.
draglayer
.
append
(
entry
);
}
return
false
;
// break
}
});
}
}
this
.
draglayer
.
show
();
this
.
drag_active
=
true
;
this
.
triggerEvent
(
'dragstart'
);
}
if
(
this
.
drag_active
&&
this
.
draglayer
)
{
var
pos
=
rcube_event
.
get_mouse_pos
(
e
);
this
.
draglayer
.
css
({
left
:
(
pos
.
x
+
20
)
+
'px'
,
top
:
(
pos
.
y
-
5
+
(
bw
.
ie
?
document
.
documentElement
.
scrollTop
:
0
))
+
'px'
});
this
.
triggerEvent
(
'dragmove'
,
e
?
e
:
window
.
event
);
}
this
.
drag_start
=
false
;
return
false
;
},
/**
* Handler for mouse up events
*/
drag_mouse_up
:
function
(
e
)
{
document
.
onmousemove
=
null
;
if
(
e
.
type
==
'touchend'
)
{
if
(
e
.
changedTouches
.
length
!=
1
)
return
rcube_event
.
cancel
(
e
);
}
if
(
this
.
draglayer
&&
this
.
draglayer
.
is
(
':visible'
))
{
if
(
this
.
drag_start_pos
)
this
.
draglayer
.
animate
(
this
.
drag_start_pos
,
300
,
'swing'
).
hide
(
20
);
else
this
.
draglayer
.
hide
();
}
if
(
this
.
drag_active
)
this
.
focus
();
this
.
drag_active
=
false
;
rcube_event
.
remove_listener
({
event
:
'mousemove'
,
object
:
this
,
method
:
'drag_mouse_move'
});
rcube_event
.
remove_listener
({
event
:
'mouseup'
,
object
:
this
,
method
:
'drag_mouse_up'
});
if
(
bw
.
mobile
)
{
rcube_event
.
remove_listener
({
event
:
'touchmove'
,
object
:
this
,
method
:
'drag_mouse_move'
});
rcube_event
.
remove_listener
({
event
:
'touchend'
,
object
:
this
,
method
:
'drag_mouse_up'
});
}
// remove temp divs
this
.
del_dragfix
();
this
.
triggerEvent
(
'dragend'
,
e
);
return
rcube_event
.
cancel
(
e
);
},
/**
* Handler for mouse move events for dragging list column
*/
column_drag_mouse_move
:
function
(
e
)
{
if
(
this
.
drag_start
)
{
// check mouse movement, of less than 3 pixels, don't start dragging
var
i
,
m
=
rcube_event
.
get_mouse_pos
(
e
);
if
(
!
this
.
drag_mouse_start
||
(
Math
.
abs
(
m
.
x
-
this
.
drag_mouse_start
.
x
)
<
3
&&
Math
.
abs
(
m
.
y
-
this
.
drag_mouse_start
.
y
)
<
3
))
return
false
;
if
(
!
this
.
col_draglayer
)
{
var
lpos
=
$
(
this
.
list
).
offset
(),
cells
=
this
.
thead
.
rows
[
0
].
cells
;
// create dragging layer
this
.
col_draglayer
=
$
(
'<div>'
).
attr
(
'id'
,
'rcmcoldraglayer'
)
.
css
(
lpos
).
css
({
position
:
'absolute'
,
'z-index'
:
2001
,
'background-color'
:
'white'
,
opacity
:
0.75
,
height
:
(
this
.
frame
.
offsetHeight
-
2
)
+
'px'
,
width
:
(
this
.
frame
.
offsetWidth
-
2
)
+
'px'
})
.
appendTo
(
document
.
body
)
// ... and column position indicator
.
append
(
$
(
'<div>'
).
attr
(
'id'
,
'rcmcolumnindicator'
)
.
css
({
position
:
'absolute'
,
'border-right'
:
'2px dotted #555'
,
'z-index'
:
2002
,
height
:
(
this
.
frame
.
offsetHeight
-
2
)
+
'px'
}));
this
.
cols
=
[];
this
.
list_pos
=
this
.
list_min_pos
=
lpos
.
left
;
// save columns positions
for
(
i
=
0
;
i
<
cells
.
length
;
i
++
)
{
this
.
cols
[
i
]
=
cells
[
i
].
offsetWidth
;
if
(
this
.
column_fixed
!==
null
&&
i
<=
this
.
column_fixed
)
{
this
.
list_min_pos
+=
this
.
cols
[
i
];
}
}
}
this
.
col_draglayer
.
show
();
this
.
col_drag_active
=
true
;
this
.
triggerEvent
(
'column_dragstart'
);
}
// set column indicator position
if
(
this
.
col_drag_active
&&
this
.
col_draglayer
)
{
var
i
,
cpos
=
0
,
pos
=
rcube_event
.
get_mouse_pos
(
e
);
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
;
}
// handle fixed columns on left
if
(
i
==
0
&&
this
.
list_min_pos
>
pos
.
x
)
cpos
=
this
.
list_min_pos
-
this
.
list_pos
;
// empty list needs some assignment
else
if
(
!
this
.
list
.
rowcount
&&
i
==
this
.
cols
.
length
)
cpos
-=
2
;
$
(
'#rcmcolumnindicator'
).
css
({
width
:
cpos
+
'px'
});
this
.
triggerEvent
(
'column_dragmove'
,
e
?
e
:
window
.
event
);
}
this
.
drag_start
=
false
;
return
false
;
},
/**
* Handler for mouse up events for dragging list columns
*/
column_drag_mouse_up
:
function
(
e
)
{
document
.
onmousemove
=
null
;
if
(
this
.
col_draglayer
)
{
(
this
.
col_draglayer
).
remove
();
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
);
// 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
);
},
/**
* Returns IDs of all rows in a thread (except root) for specified root
*/
row_children
:
function
(
uid
)
{
if
(
!
this
.
rows
[
uid
]
||
!
this
.
rows
[
uid
].
has_children
)
return
[];
var
res
=
[],
depth
=
this
.
rows
[
uid
].
depth
,
row
=
this
.
rows
[
uid
].
obj
.
nextSibling
;
while
(
row
)
{
if
(
row
.
nodeType
==
1
)
{
if
((
r
=
this
.
rows
[
row
.
uid
]))
{
if
(
!
r
.
depth
||
r
.
depth
<=
depth
)
break
;
res
.
push
(
r
.
uid
);
}
}
row
=
row
.
nextSibling
;
}
return
res
;
},
/**
* Creates a layer for drag&drop over iframes
*/
add_dragfix
:
function
()
{
$
(
'iframe'
).
each
(
function
()
{
$
(
'<div class="iframe-dragdrop-fix"></div>'
)
.
css
({
background
:
'#fff'
,
width
:
this
.
offsetWidth
+
'px'
,
height
:
this
.
offsetHeight
+
'px'
,
position
:
'absolute'
,
opacity
:
'0.001'
,
zIndex
:
1000
})
.
css
(
$
(
this
).
offset
())
.
appendTo
(
document
.
body
);
});
},
/**
* Removes the layer for drag&drop over iframes
*/
del_dragfix
:
function
()
{
$
(
'div.iframe-dragdrop-fix'
).
each
(
function
()
{
this
.
parentNode
.
removeChild
(
this
);
});
},
/**
* Replaces two columns
*/
column_replace
:
function
(
from
,
to
)
{
// only supported for <table> lists
if
(
!
this
.
thead
||
!
this
.
thead
.
rows
)
return
;
var
len
,
cells
=
this
.
thead
.
rows
[
0
].
cells
,
elem
=
cells
[
from
],
before
=
cells
[
to
],
td
=
document
.
createElement
(
'td'
);
// replace header cells
if
(
before
)
cells
[
0
].
parentNode
.
insertBefore
(
td
,
before
);
else
cells
[
0
].
parentNode
.
appendChild
(
td
);
cells
[
0
].
parentNode
.
replaceChild
(
elem
,
td
);
// replace list cells
for
(
r
=
0
,
len
=
this
.
tbody
.
rows
.
length
;
r
<
len
;
r
++
)
{
row
=
this
.
tbody
.
rows
[
r
];
elem
=
row
.
cells
[
from
];
before
=
row
.
cells
[
to
];
td
=
document
.
createElement
(
'td'
);
if
(
before
)
row
.
insertBefore
(
td
,
before
);
else
row
.
appendChild
(
td
);
row
.
replaceChild
(
elem
,
td
);
}
// update subject column position
if
(
this
.
subject_col
==
from
)
this
.
subject_col
=
to
>
from
?
to
-
1
:
to
;
else
if
(
this
.
subject_col
<
from
&&
to
<=
this
.
subject_col
)
this
.
subject_col
++
;
else
if
(
this
.
subject_col
>
from
&&
to
>=
this
.
subject_col
)
this
.
subject_col
--
;
this
.
triggerEvent
(
'column_replace'
);
}
};
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
;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 9, 12:49 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
506961
Default Alt Text
list.js (36 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment