@ -4,7 +4,7 @@
* @ licstart The following is the entire license notice for the
* @ licstart The following is the entire license notice for the
* JavaScript code in this file .
* JavaScript code in this file .
*
*
* Copyright ( C ) Philip Weir
* Copyright ( C ) 2018 - 2019 Philip Weir
*
*
* The JavaScript code in this page is free software : you can redistribute it
* 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
* and / or modify it under the terms of the GNU General Public License
@ -16,11 +16,6 @@
* /
* /
rcube _webmail . prototype . swipe = {
rcube _webmail . prototype . swipe = {
container _class : 'swipe-container' ,
button _class : 'swipe-action' ,
label _class : 'swipe-label' ,
element : null ,
position _target : function ( obj , pos , transition , max _move ) {
position _target : function ( obj , pos , transition , max _move ) {
var translate = '' ;
var translate = '' ;
@ -34,9 +29,7 @@ rcube_webmail.prototype.swipe = {
}
}
}
}
// Edge (Trident) does not support transform on <tr>s
if ( bw . edge && $ ( obj ) . is ( 'tr' ) ) { // Edge does not support transform on <tr>s
// Roundcube 1.4 detects Edge Trident version as 537.36 see #6952
if ( bw . edge && ( bw . vendver < 75 || bw . vendver > 537 ) && $ ( obj ) . is ( 'tr' ) ) {
$ ( obj ) . children ( 'td' ) . css ( 'transform' , translate ) ;
$ ( obj ) . children ( 'td' ) . css ( 'transform' , translate ) ;
}
}
else {
else {
@ -48,8 +41,8 @@ rcube_webmail.prototype.swipe = {
if ( ! props . uid )
if ( ! props . uid )
return ;
return ;
var prev _uid = rcmail . env [ rcmail . env . swipe_selection _id ] ;
var prev _uid = rcmail . env [ rcmail . env . task == 'addressbook' ? 'cid' : 'uid' ] ;
rcmail . env [ rcmail . env . swipe_selection _id ] = props . uid ;
rcmail . env [ rcmail . env . task == 'addressbook' ? 'cid' : 'uid' ] = props . uid ;
var type = null ;
var type = null ;
if ( matches = command . match ( /([a-z0-9_-]+)\/([a-z0-9-_]+)/ ) ) {
if ( matches = command . match ( /([a-z0-9_-]+)\/([a-z0-9-_]+)/ ) ) {
@ -61,7 +54,8 @@ rcube_webmail.prototype.swipe = {
rcmail . mark _message ( command ) ;
rcmail . mark _message ( command ) ;
}
}
else if ( type == 'compose' ) {
else if ( type == 'compose' ) {
rcmail . command ( command , '' , props . obj , props . originalEvent , true ) ;
rcmail . enable _command ( command , true ) ;
rcmail . command ( command , '' , props . obj , props . originalEvent ) ;
}
}
else if ( type == 'select' ) {
else if ( type == 'select' ) {
rcmail . env . swipe _list . highlight _row ( props . uid , true ) ;
rcmail . env . swipe _list . highlight _row ( props . uid , true ) ;
@ -78,7 +72,7 @@ rcube_webmail.prototype.swipe = {
rcmail . enable _command ( command , prev _command ) ;
rcmail . enable _command ( command , prev _command ) ;
}
}
rcmail . env [ rcmail . env . swipe_selection _id ] = prev _uid ;
rcmail . env [ rcmail . env . task == 'addressbook' ? 'cid' : 'uid' ] = prev _uid ;
} ,
} ,
select _action : function ( direction , obj ) {
select _action : function ( direction , obj ) {
@ -139,7 +133,7 @@ rcube_webmail.prototype.swipe = {
'command' : obj && obj . hasClass ( 'flagged' ) ? 'mark/unflagged' : 'mark/flagged'
'command' : obj && obj . hasClass ( 'flagged' ) ? 'mark/unflagged' : 'mark/flagged'
} ,
} ,
'swipe-select' : {
'swipe-select' : {
'class' : ( obj && obj . hasClass ( 'selected' ) ? 'select invert' : 'select ion ') + ' swipe_active' ,
'class' : ( obj && obj . hasClass ( 'selected' ) ? 'select invert' : 'select all ') + ' swipe_active' ,
'text' : obj && obj . hasClass ( 'selected' ) ? 'swipe.deselect' : 'select' ,
'text' : obj && obj . hasClass ( 'selected' ) ? 'swipe.deselect' : 'select' ,
'command' : obj && obj . hasClass ( 'selected' ) ? 'select/deselect' : 'select/select'
'command' : obj && obj . hasClass ( 'selected' ) ? 'select/deselect' : 'select/select'
} ,
} ,
@ -180,30 +174,22 @@ rcube_webmail.prototype.swipe = {
'moveevent' : 'pointermove' ,
'moveevent' : 'pointermove' ,
'endevent' : 'pointerup' ,
'endevent' : 'pointerup' ,
'cancelevent' : 'pointercancel' ,
'cancelevent' : 'pointercancel' ,
'minmove' : 5 ,
'id' : function ( e ) { return e . pointerId ; } ,
'id' : function ( e ) { return e . pointerId ; } ,
'type' : function ( e ) { return e . pointerType ; } ,
'type' : function ( e ) { return e . pointerType ; } ,
'pos' : function ( e , x ) { return e . originalEvent [ x ? 'pageX' : 'pageY' ] ; } ,
'pos' : function ( e , x ) { return e . originalEvent [ x ? 'pageX' : 'pageY' ] ; } ,
'clearswipe' : function ( e ) {
'clearswipe' : function ( e ) {
rcmail . swipe . position _target ( opts [ swipedata . axis ] . target _obj , 0 ) ;
rcmail . swipe . position _target ( opts [ swipedata . axis ] . target _obj , 0 ) ;
opts [ swipedata . axis ] . target _obj . removeClass ( 'swipe-active' ) ;
opts [ swipedata . axis ] . target _obj . removeClass ( 'swipe-active' ) ;
swipedata = { } ;
rcmail . swipe . active = null ;
// reset #swipe-action
// reset #swipe-action
$ ( '#swipe-action' ) . removeClass ( ) . hide ( ) ;
$ ( '#swipe-action' ) . removeClass ( ) . hide ( ) ;
$ ( '.swipe-container' ) . attr ( 'class' , rcmail . swipe . container _class ) ;
$ ( '.swipe-container' ) . attr ( 'class' , rcmail . env . swipe _container _class ) ;
$ ( '.swipe-action' ) . attr ( 'class' , rcmail . swipe . button _class ) ;
$ ( '.swipe-action' ) . attr ( 'class' , rcmail . env . swipe _button _class ) ;
rcmail . swipe . set _scroll _css ( ) ;
if ( opts . parent _obj )
if ( opts . parent _obj )
opts . parent _obj . off ( swipeevents . moveevent , rcube _event . cancel ) ;
opts . parent _obj . off ( swipeevents . moveevent , rcube _event . cancel ) ;
// restore normal scrolling on touch devices
if ( swipedata . axis == 'vertical' && ! bw . pointer ) {
rcmail . swipe . parent . css ( 'overflow-y' , 'auto' ) ;
}
swipedata = { } ;
rcmail . swipe . active = null ;
}
}
} ;
} ;
var swipedata = { } ;
var swipedata = { } ;
@ -214,7 +200,6 @@ rcube_webmail.prototype.swipe = {
swipeevents . moveevent = 'touchmove' ;
swipeevents . moveevent = 'touchmove' ;
swipeevents . endevent = 'touchend' ;
swipeevents . endevent = 'touchend' ;
swipeevents . cancelevent = 'touchcancel' ;
swipeevents . cancelevent = 'touchcancel' ;
swipeevents . minmove = 15 ;
swipeevents . id = function ( e ) { return e . changedTouches . length == 1 ? e . changedTouches [ 0 ] . identifier : - 1 ; } ;
swipeevents . id = function ( e ) { return e . changedTouches . length == 1 ? e . changedTouches [ 0 ] . identifier : - 1 ; } ;
swipeevents . type = function ( e ) { return 'touch' ; } ;
swipeevents . type = function ( e ) { return 'touch' ; } ;
swipeevents . pos = function ( e , x ) { return e . originalEvent . targetTouches [ 0 ] [ x ? 'pageX' : 'pageY' ] ; } ;
swipeevents . pos = function ( e , x ) { return e . originalEvent . targetTouches [ 0 ] [ x ? 'pageX' : 'pageY' ] ; } ;
@ -228,7 +213,6 @@ rcube_webmail.prototype.swipe = {
swipedata . y = swipeevents . pos ( e , false ) ;
swipedata . y = swipeevents . pos ( e , false ) ;
swipedata . id = swipeevents . id ( e ) ;
swipedata . id = swipeevents . id ( e ) ;
swipedata . scrollable = rcmail . swipe . parent [ 0 ] . offsetHeight < rcmail . swipe . parent [ 0 ] . scrollHeight ;
swipedata . scrollable = rcmail . swipe . parent [ 0 ] . offsetHeight < rcmail . swipe . parent [ 0 ] . scrollHeight ;
swipedata . scrolltop = rcmail . swipe . parent . scrollTop ( ) ;
if ( opts . parent _obj )
if ( opts . parent _obj )
opts . parent _obj . off ( swipeevents . moveevent , rcube _event . cancel ) ;
opts . parent _obj . off ( swipeevents . moveevent , rcube _event . cancel ) ;
@ -247,7 +231,7 @@ rcube_webmail.prototype.swipe = {
changeX = opts . horizontal ? ( changeX < 0 ? Math . max ( opts . horizontal . maxmove * - 1 , changeX ) : Math . min ( opts . horizontal . maxmove , changeX ) ) : 0 ;
changeX = opts . horizontal ? ( changeX < 0 ? Math . max ( opts . horizontal . maxmove * - 1 , changeX ) : Math . min ( opts . horizontal . maxmove , changeX ) ) : 0 ;
// use Math.abs() to ensure value is always a positive number
// use Math.abs() to ensure value is always a positive number
var min _move = swipeevents . minmove ; // the minimum amount of pointer movement required to trigger the swipe
var min _move = 5 ; // the minimum amount of pointer movement required to trigger the swipe
var temp _axis ;
var temp _axis ;
if ( opts . vertical && ( Math . abs ( changeY ) > min _move || opts . vertical . target _obj . hasClass ( 'swipe-active' ) ) ) {
if ( opts . vertical && ( Math . abs ( changeY ) > min _move || opts . vertical . target _obj . hasClass ( 'swipe-active' ) ) ) {
temp _axis = 'vertical' ;
temp _axis = 'vertical' ;
@ -265,17 +249,14 @@ rcube_webmail.prototype.swipe = {
// do not interfere with normal list scrolling
// do not interfere with normal list scrolling
if ( temp _axis == 'vertical' && rcmail . swipe . parent . scrollTop ( ) != 0 ) {
if ( temp _axis == 'vertical' && rcmail . swipe . parent . scrollTop ( ) != 0 ) {
if ( swipedata. scrollable )
if ( bw. pointer && swipedata. scrollable )
rcmail . swipe . set_scroll _css ( ) ;
rcmail . swipe . parent. css ( 'touch-action' , 'pan-y' ) ;
if ( swipedata . axis )
if ( swipedata . axis )
swipeevents . clearswipe ( e ) ;
swipeevents . clearswipe ( e ) ;
return ;
return ;
}
}
else if ( temp _axis == 'horizontal' && ! bw . pointer && swipedata . scrolltop != rcmail . swipe . parent . scrollTop ( ) ) {
return ;
}
// save the axis info
// save the axis info
swipedata . axis = temp _axis ;
swipedata . axis = temp _axis ;
@ -287,8 +268,8 @@ rcube_webmail.prototype.swipe = {
return ;
return ;
$ ( '#swipe-action' ) . attr ( 'class' , temp _axis ) . data ( 'callback' , action . callback ) ;
$ ( '#swipe-action' ) . attr ( 'class' , temp _axis ) . data ( 'callback' , action . callback ) ;
$ ( '.swipe-container' ) . attr ( 'class' , rcmail . swipe. container_class + ' ' + direction ) ;
$ ( '.swipe-container' ) . attr ( 'class' , rcmail . env. swipe_ container_class + ' ' + direction ) ;
$ ( '.swipe-action' ) . attr ( 'class' , rcmail . swipe. button_class + ' ' + action . class ) ;
$ ( '.swipe-action' ) . attr ( 'class' , rcmail . env. swipe_ button_class + ' ' + action . class ) ;
$ ( '.swipe-label' ) . text ( rcmail . gettext ( action . text ) ) ;
$ ( '.swipe-label' ) . text ( rcmail . gettext ( action . text ) ) ;
if ( ! opts [ swipedata . axis ] . target _obj . hasClass ( 'swipe-active' ) ) {
if ( ! opts [ swipedata . axis ] . target _obj . hasClass ( 'swipe-active' ) ) {
@ -304,21 +285,17 @@ rcube_webmail.prototype.swipe = {
if ( opts . parent _obj )
if ( opts . parent _obj )
opts . parent _obj . on ( swipeevents . moveevent , rcube _event . cancel ) ;
opts . parent _obj . on ( swipeevents . moveevent , rcube _event . cancel ) ;
// prevent up scroll when vertical active on touch devices
if ( rcmail . swipe . active == 'vertical' && ! bw . pointer && changeY > 0 )
rcmail . swipe . parent . css ( 'overflow-y' , 'hidden' ) ;
}
}
// the user must swipe a certain about before the action is activated, try to prevent accidental actions
// the user must swipe a certain about before the action is activated, try to prevent accidental actions
// do not activate if there is no callback
// do not activate if there is no callback
if ( ( ( swipedata . axis == 'vertical' && changeY > opts [ swipedata . axis ] . minmove ) ||
if ( ( ( swipedata . axis == 'vertical' && changeY > opts [ swipedata . axis ] . minmove ) ||
( swipedata . axis == 'horizontal' && ( changeX < ( opts [ swipedata . axis ] . minmove * - 1 ) || changeX > opts [ swipedata . axis ] . minmove ) ) ) && action . callback ) {
( swipedata . axis == 'horizontal' && ( changeX < ( opts [ swipedata . axis ] . minmove * - 1 ) || changeX > opts [ swipedata . axis ] . minmove ) ) ) && action . callback ) {
$ ( '#swipe-action .horizontal,#swipe-action.vertical > .swipe-container ') . addClass ( action . class ) ;
$ ( '#swipe-action ') . addClass ( action . class ) ;
}
}
else {
else {
// reset the swipe if the user takes the row back to the start
// reset the swipe if the user takes the row back to the start
$ ( '#swipe-action .horizontal,#swipe-action.vertical > .swipe-container ') . removeClass ( action . class ) ;
$ ( '#swipe-action ') . removeClass ( action . class ) ;
$ ( '#swipe-action' ) . data ( 'callback' , null ) ;
$ ( '#swipe-action' ) . data ( 'callback' , null ) ;
}
}
@ -339,31 +316,25 @@ rcube_webmail.prototype.swipe = {
if ( swipedata . axis )
if ( swipedata . axis )
swipeevents . clearswipe ( e ) ;
swipeevents . clearswipe ( e ) ;
} ) ;
} ) ;
} ,
set _scroll _css : function ( ) {
// Edge (Trident) does not support pan-down, only pan-y
if ( bw . pointer && rcmail . swipe . parent . scrollTop ( ) == 0 && ! ( bw . edge && bw . vendver < 75 ) ) {
// allow vertical pointer events to fire (if one is configured)
var action = rcmail . swipe . select _action ( 'down' ) ;
rcmail . swipe . parent . css ( 'touch-action' , action . callback ? 'pan-down' : 'pan-y' ) ;
}
else {
rcmail . swipe . parent . css ( 'touch-action' , 'pan-y' ) ;
}
}
}
} ;
} ;
$ ( document ) . ready ( function ( ) {
$ ( document ) . ready ( function ( ) {
if ( window . rcmail && ( ( bw . touch && ! bw . ie ) || bw . pointer ) ) {
if ( window . rcmail && ( ( bw . touch && ! bw . ie ) || bw . pointer ) ) {
rcmail . addEventListener ( 'init' , function ( ) {
rcmail . addEventListener ( 'init' , function ( ) {
rcmail . env . swipe _list = rcmail [ rcmail . env . swipe _list _name ] ;
rcmail . env . swipe _list = rcmail . task == 'addressbook' ? rcmail . contact _list : rcmail . message _list ;
rcmail . env . swipe _menuname = 'messagelistmenu' ;
rcmail . env . swipe _container _class = 'swipe-container toolbarmenu' ;
rcmail . env . swipe _button _class = 'swipe-action' ;
var list _container = $ ( rcmail . env . swipe _list . list ) . parent ( ) ;
var list _container = $ ( rcmail . env . swipe _list . list ) . parent ( ) ;
if ( rcmail . env . swipe _list . draggable || ! list _container [ 0 ] . addEventListener )
if ( rcmail . env . swipe _list . draggable || ! list _container [ 0 ] . addEventListener )
return ;
return ;
var swipe _action = $ ( '<div>' ) . attr ( 'id' , 'swipe-action' ) . append ( rcmail . swipe . element ) ;
// minic toolbarmenu structure to pickup CSS from core
var swipe _action = $ ( '<div>' ) . attr ( 'id' , 'swipe-action' ) . append (
$ ( '<ul>' ) . addClass ( rcmail . env . swipe _container _class ) . append ( $ ( '<li>' ) . append ( $ ( '<a>' ) . addClass ( rcmail . env . swipe _button _class ) . append ( $ ( '<span>' ) . addClass ( 'swipe-label' ) ) ) )
) ;
rcmail . swipe . parent = list _container ;
rcmail . swipe . parent = list _container ;
rcmail . swipe . parent . prepend ( swipe _action . hide ( ) ) ;
rcmail . swipe . parent . prepend ( swipe _action . hide ( ) ) ;
@ -434,14 +405,27 @@ $(document).ready(function() {
rcmail . swipe . init ( swipe _config ) ;
rcmail . swipe . init ( swipe _config ) ;
// prevent accidental list scroll when swipe active
// prevent accidental list scroll when swipe active
rcmail . swipe . parent . on ( 'scroll' , function ( ) { rcmail . swipe . set _scroll _css ( ) ; } ) . trigger ( 'scroll' ) ;
rcmail . swipe . parent . on ( 'scroll' , function ( ) {
if ( ! bw . pointer ) {
rcmail . env . swipe _list . addEventListener ( 'getselection' , function ( p ) {
if ( rcmail . swipe . active )
if ( rcmail . swipe . active && rcmail . env [ rcmail . env . swipe _selection _id ] ) {
return false ;
p . res = [ rcmail . env [ rcmail . env . swipe _selection _id ] ] ;
return false ;
}
}
} ) ;
else if ( $ ( this ) . scrollTop ( ) == 0 ) {
// allow vertical pointer events to fire (if one is configured)
var action = rcmail . swipe . select _action ( 'down' ) ;
// Edge does not support pan-down, only pan-y
rcmail . swipe . parent . css ( 'touch-action' , action . callback && ! bw . edge ? 'pan-down' : 'pan-y' ) ;
}
} ) . trigger ( 'scroll' ) ;
if ( rcmail . env . task == 'addressbook' ) {
rcmail . contact _list . addEventListener ( 'getselection' , function ( p ) {
if ( $ ( '.swipe-active' ) . length == 1 && rcmail . env . cid ) {
p . res = [ rcmail . env . cid ] ;
return false ;
}
} ) ;
}
} ) ;
} ) ;
// right/left/down swipe on list
// right/left/down swipe on list
@ -462,7 +446,7 @@ $(document).ready(function() {
'transition' : 'translatex' ,
'transition' : 'translatex' ,
'action_sytle' : function ( o ) {
'action_sytle' : function ( o ) {
return {
return {
'top' : o . position ( ) . top + ( bw . mz ? rcmail . swipe . parent . scrollTop ( ) : 0 ) ,
'top' : o . position ( ) . top ,
'left' : o . position ( ) . left ,
'left' : o . position ( ) . left ,
'width' : o . width ( ) + 'px' ,
'width' : o . width ( ) + 'px' ,
'height' : ( o . height ( ) - 2 ) + 'px' // subtract the border
'height' : ( o . height ( ) - 2 ) + 'px' // subtract the border