Compare commits

..

31 Commits

Author SHA1 Message Date
PhilW 884c2bd51b update plugin repo url 6 years ago
PhilW b573ac7c26 remove repositories section from composer.json, its a root-only prop 6 years ago
PhilW 20174baa10 add release mark 6 years ago
PhilW 6bd2f90e92 update after rc cb8c078 6 years ago
PhilW b051b8a58e add version to changelog 6 years ago
PhilW 8998583c8e a few more style tweaks 6 years ago
PhilW 9d6ce623da a few style tweaks and improvements 6 years ago
PhilW cd4b8fd19a use correct colour var 6 years ago
PhilW c0515ac484 use better colours 6 years ago
PhilW 2e63bae2d1 bump git-master version 6 years ago
PhilW 1558bbbb27 tweak Edge browser detection 6 years ago
PhilW 1393f9d3ff small CS cleanup 6 years ago
PhilW 38181a034f add release header to changelog 6 years ago
PhilW 13f177efb8 remove redundant type attrib in script tag 6 years ago
PhilW c5c57fdd9f update minified css 6 years ago
PhilW 2a38664092 use empty() rather than count() 6 years ago
PhilW a0d1a33e56 a few teaks to readme 6 years ago
PhilW 198ab390be remove year(s) from copyright headers 6 years ago
PhilW ae9671c770 use 1.4-dev as min version req until 1.4 release 6 years ago
PhilW d796306abb fix php 7.2 compat (#10) 7 years ago
PhilW 86fb57a355 correct JS var name 7 years ago
PhilW 768c0d72c9 Merge branch 'dev/elastic' 7 years ago
PhilW ae74720cb7 replace swipe_actions_list hook with swipe_actions, improve extensibility 7 years ago
PhilW 7d7d5eb71f more improvements for touch devices 7 years ago
PhilW 85bcbfecba fix 3f9071c (#8) 7 years ago
PhilW 91a24255f2 update after rc f1e911e 7 years ago
PhilW d728f118c2 make plugin more skinable 7 years ago
PhilW 3f9071cad3 remove dupe code 7 years ago
PhilW b7e0161771 fix touch event support 7 years ago
PhilW 04f8ba9b30 Merge branch 'dev_contacts' 7 years ago
PhilW 020a319004 remove redundant css after rc 3c76009 7 years ago

@ -1,6 +1,18 @@
Roundcube Webmail Swipe
=======================
Version 0.3 (2020-04-27, rc-1.4.4)
=================================================
* Update command enabling after (req RC cb8c078)
Version 0.2 (2020-01-03, rc-1.4.2)
=================================================
* Better use of colours from core
Version 0.1 (2019-10-27, rc-1.4)
=================================================
* Add swipe support on contacts list
* Move swipe options to their own dialog
* Replace swipeactions with swipeoptions
* Use listoptions template container (req RC 03425d1)
* Allow menu to use select or radio buttons

@ -21,11 +21,6 @@ as a linked part of the plugin and therefore skins DO NOT fall under the
provisions of the GPL license. See the README file located in the core skins
folder for details on the skin license.
Known issues
------------
* No support in IE
* No vertical swipe in Edge, no support for `touch-action: pan-down;` CSS - [bug report](https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10573036/)
Install
-------
* Place this plugin folder into plugins directory of Roundcube
@ -39,6 +34,15 @@ Supported skins
---------------
* Elastic
Supported browsers
------------------
This plugin relies on [Pointer Events][pointer] with fallback support for
[Touch Events][touch] and should work in any browser which supports either of
these, such as: Chrome, Firefox, or Safari. When used with Edge there is no
support for vertical swipe actions, this is because the browser does not
support the `touch-action: pan-down;` CSS property - [bug report][edge].
There is no support for Internet Explorer.
Configuration
-------------
To set the default actions add the following to your Roundcube config file:
@ -106,13 +110,28 @@ to dont_override:
Interaction with other plugins
------------------------------
The `swipe_actions_list` hook is triggered when listing the available actions
The `swipe_actions` hook is triggered when the plugin starts up
on the list options menu.
*Arguments:*
* actions
* direction
* list_type - the name of list the swipe actions are being performed on, e.g. messagelist, used when selecting/saving config
* actions - an array of actions for this list in the format:
```
$args['actions'] = array(
'list_name' => '*JS list object name*',
'selection_id' => '*JS element identifier e.g. UID*',
'vertical' => array(
'*action_name*' => array('label' => '*display name*'),
...
),
'horizontal' => array(
'*action_name*' => array('label' => '*display name*'),
...
)
);
```
*Return values:*
* list_type
* actions
The `swipe-action` JS event is triggered when a swipe action is performed.
@ -129,6 +148,9 @@ an action:
Note: Only 1 of callback and command need to be supplied. If no callback is
defined then the command is passed to the standard Swipe callback function.
[rcplugrepo]: https://plugins.roundcube.net/packages/johndoh/swipe
[rcplugrepo]: https://plugins.roundcube.net/#/packages/johndoh/swipe
[releases]: https://github.com/johndoh/roundcube-swipe/releases
[gpl]: https://www.gnu.org/licenses/gpl.html
[gpl]: https://www.gnu.org/licenses/gpl.html
[pointer]: https://caniuse.com/#feat=pointer
[touch]: https://caniuse.com/#feat=touch
[edge]: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10573036/

@ -5,7 +5,7 @@
"homepage": "https://github.com/johndoh/roundcube-swipe/",
"license": "GPL-3.0",
"type": "roundcube-plugin",
"version": "0.1-git",
"version": "0.3-git",
"authors": [
{
"name": "Philip Weir",
@ -13,19 +13,13 @@
"role": "Developer"
}
],
"repositories": [
{
"type": "composer",
"url": "https://plugins.roundcube.net"
}
],
"require": {
"php": ">=5.2.1",
"roundcube/plugin-installer": ">=0.1.2"
},
"extra": {
"roundcube": {
"min-version": "1.4"
"min-version": "1.4-git"
}
}
}

@ -18,4 +18,8 @@
<roundcube:object name="swipeoptionslist" type="select" direction="down" />
</div>
</div>
</div>
</div>
<script>
rcmail.swipe.container_class += ' menu';
rcmail.swipe.element = $('<ul>').addClass(rcmail.swipe.container_class).append($('<li>').append($('<a>').addClass(rcmail.swipe.button_class).append($('<span>').addClass(rcmail.swipe.label_class))));
</script>

@ -5,6 +5,10 @@
@import (reference) "../../../../skins/elastic/styles/variables";
@import (reference) "../../../../skins/elastic/styles/mixins";
// Calculate default colors from default list background color
@color-swipe-default-background: contrast(@color-layout-list-background, darken(@color-layout-list-background, 10%), lighten(@color-layout-list-background, 40%));
@color-swipe-default: contrast(@color-swipe-default-background, lighten(@color-swipe-default-background, 30%), darken(@color-swipe-default-background, 40%), 57%);
#swipe-action {
position: absolute;
display: flex;
@ -12,54 +16,38 @@
border-collapse: collapse;
&.horizontal {
background-color: lighten(@color-black, 85%);
color: lighten(@color-black, 50%);
&.swipe_active,
&.swipe_mark {
background-color: fadeout(@color-main, 85%);
color: @color-main;
}
&.swipe_danger {
background-color: @color-message-error-box-background;
color: @color-message-error;
}
&.swipe_move {
background-color: @color-message-warning-box-background;
color: @color-message-warning;
}
&.swipe_success,
&.swipe_compose {
background-color: @color-message-success-box-background;
color: @color-message-success;
}
background-color: @color-swipe-default-background;
color: @color-swipe-default;
}
&.vertical {
background-color: transparent;
color: lighten(@color-black, 70%);
top: 2em;
height: 1.5em;
z-index: 1000;
color: @color-swipe-default;
}
&.horizontal,
&.vertical > .swipe-container {
&.swipe_active,
&.swipe_mark {
color: @color-main;
background-color: @color-message-information;
color: @color-message-text;
}
&.swipe_move {
color: @color-message-warning;
&.swipe_danger {
background-color: @color-message-error;
color: @color-message-error-text;
}
&.swipe_danger {
color: @color-message-error;
&.swipe_move {
background-color: @color-message-warning;
color: @color-message-warning-text;
}
&.swipe_success,
&.swipe_compose {
color: @color-message-success;
background-color: @color-message-success;
color: @color-message-success-text;
}
}
@ -73,22 +61,9 @@
opacity: 1;
&::before {
margin: 0 .25em 0 .5em;
margin: 0 .5rem;
font-size: inherit
}
// icons not defined in .toolbarmenu
&.archive::before {
content: @fa-var-archive;
}
&.refresh::before {
content: @fa-var-sync;
}
&.reply.one::before {
content: @fa-var-reply;
}
}
&.left {
@ -97,21 +72,21 @@
.swipe-action::before {
float: right;
margin: 0 .5em 0 .25em;
}
}
&.down {
margin: 0 auto;
background-color: #fff;
padding: .01rem;
background-color: @color-layout-list-background;
border-radius: 50%;
box-shadow: 0 0 10px lighten(@color-black, 75%);
border: 1px solid @color-swipe-default-background;
.swipe-action {
&::before {
float: none;
padding: 0;
margin: .4em;
margin: .4rem;
padding: .25rem;
line-height: 1;
font-size: 1.2em;
width: auto;
@ -131,14 +106,14 @@
background-color: @color-layout-list-background;
}
.toolbar a.button.swipe {
.toolbar.menu a.button.swipe {
display: none;
}
// no support in IE
html.layout-small.touch:not(.ie),
html.layout-phone.touch:not(.ie) {
.toolbar {
.toolbar.menu {
a.button {
&.swipe {
display: inline-block;

@ -1 +1 @@
#listoptions-menu{overflow-y:auto;margin:-0.5em -1em;padding:.75em 1.25em}#listoptions-menu::-webkit-scrollbar{-webkit-appearance:none}#listoptions-menu::-webkit-scrollbar:vertical{width:.6rem}#listoptions-menu::-webkit-scrollbar:horizontal{height:.6rem}#listoptions-menu::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,0.4);border-radius:.3rem;border:2px solid #fff}#listoptions-menu>fieldset.swipe-menu{display:none;margin-top:1.5rem}#swipe-action{position:absolute;display:flex;align-items:center;border-collapse:collapse}#swipe-action.horizontal{background-color:#f1f3f4;color:#161b1d}#swipe-action.vertical{background-color:transparent;color:#c5cfd3;top:2em;height:1.5em}#swipe-action.checkmail{color:#37beff}#swipe-action.select,#swipe-action.deselect{background-color:#8b9fa7;color:#fff}#swipe-action.delete,#swipe-action.junk{background-color:#ff5552;color:#fff}#swipe-action.flagged,#swipe-action.unflagged,#swipe-action.read,#swipe-action.unread{background-color:#37beff;color:#fff}#swipe-action.forward,#swipe-action.reply,#swipe-action.replyall,#swipe-action.notjunk{background-color:#41b849;color:#fff}#swipe-action.move,#swipe-action.archive{background-color:#ffd452;color:#fff}#swipe-action>.swipe-container>.swipe-action{line-height:100%;font-size:1.2em}#swipe-action>.swipe-container>.swipe-action::before{font-size:1.25em;display:block;float:left;margin:0 .25rem 0 0;width:1.18em;height:1em;font-family:'Icons';font-style:normal;font-weight:900;text-decoration:inherit;text-align:center;speak:none;font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;margin:0 .25em 0 .5em}#swipe-action>.swipe-container>.swipe-action.archive::before{content:"\f187"}#swipe-action>.swipe-container>.swipe-action.checkmail::before{content:"\f021"}#swipe-action>.swipe-container>.swipe-action.delete::before{content:"\f2ed"}#swipe-action>.swipe-container>.swipe-action.flagged::before{content:"\f024"}#swipe-action>.swipe-container>.swipe-action.unflagged::before{content:"\f024";font-weight:400}#swipe-action>.swipe-container>.swipe-action.forward::before{content:"\f064"}#swipe-action>.swipe-container>.swipe-action.junk::before{content:"\f7e4"}#swipe-action>.swipe-container>.swipe-action.notjunk::before{content:"\f01c"}#swipe-action>.swipe-container>.swipe-action.move::before{content:"\f0b2"}#swipe-action>.swipe-container>.swipe-action.read::before{content:"\f111";font-weight:400}#swipe-action>.swipe-container>.swipe-action.unread::before{content:"\f111"}#swipe-action>.swipe-container>.swipe-action.reply::before{content:"\f3e5"}#swipe-action>.swipe-container>.swipe-action.replyall::before{content:"\f122"}#swipe-action>.swipe-container>.swipe-action.select::before{content:"\f14a";font-weight:400}#swipe-action>.swipe-container>.swipe-action.deselect::before{content:"\f0c8";font-weight:400}#swipe-action>.swipe-container.left{position:absolute;right:0}#swipe-action>.swipe-container.left>.swipe-action::before{float:right;margin:0 .5em 0 .25em}#swipe-action>.swipe-container.down{margin:0 auto;background-color:#fff;border-radius:50%;box-shadow:0 0 10px #d4dbde}#swipe-action>.swipe-container.down>.swipe-action::before{float:none;padding:0;margin:10px;line-height:1em}#swipe-action>.swipe-container.down>.swipe-action>.swipe-label{display:none}.swipe-active:not(#swipe-action),.swipe-active>td{background-color:#fff}
#swipe-action{position:absolute;display:flex;align-items:center;border-collapse:collapse}#swipe-action>.swipe-container.down .swipe-action>.swipe-label,.toolbar.menu a.button.swipe{display:none}#swipe-action.horizontal{background-color:#e6e6e6;color:grey}#swipe-action.vertical{top:2em;z-index:1000;color:grey}#swipe-action.horizontal.swipe_active,#swipe-action.horizontal.swipe_mark,#swipe-action.vertical>.swipe-container.swipe_active,#swipe-action.vertical>.swipe-container.swipe_mark{background-color:#37beff;color:#fff}#swipe-action.horizontal.swipe_danger,#swipe-action.vertical>.swipe-container.swipe_danger{background-color:#ff5552;color:#fff}#swipe-action.horizontal.swipe_move,#swipe-action.vertical>.swipe-container.swipe_move{background-color:#ffd452;color:#2c363a}#swipe-action.horizontal.swipe_compose,#swipe-action.horizontal.swipe_success,#swipe-action.vertical>.swipe-container.swipe_compose,#swipe-action.vertical>.swipe-container.swipe_success{background-color:#41b849;color:#fff}#swipe-action>.swipe-container{margin:0;padding:0;list-style-type:none}#swipe-action>.swipe-container .swipe-action{font-size:1.2em;opacity:1}#swipe-action>.swipe-container .swipe-action::before{margin:0 .5rem;font-size:inherit}#swipe-action>.swipe-container.left{position:absolute;right:0}#swipe-action>.swipe-container.left .swipe-action::before{float:right}#swipe-action>.swipe-container.down{margin:0 auto;padding:.01rem;background-color:#fff;border-radius:50%;border:1px solid #e6e6e6}#swipe-action>.swipe-container.down .swipe-action::before{float:none;margin:.4rem;padding:.25rem;line-height:1;font-size:1.2em;width:auto;height:auto}.swipe-active:not(#swipe-action),.swipe-active>td{background-color:#fff}html.layout-phone.touch:not(.ie) .toolbar.menu a.button.swipe,html.layout-small.touch:not(.ie) .toolbar.menu a.button.swipe{display:inline-block}html.layout-phone.touch:not(.ie) .toolbar.menu a.button.swipe:before,html.layout-small.touch:not(.ie) .toolbar.menu a.button.swipe:before{content:"\f25a"}html.edge #swipeoptionsmenu>.swipeoptions-down{display:none}

@ -4,7 +4,7 @@
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (C) 2018-2019 Philip Weir
* Copyright (C) Philip Weir
*
* 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
@ -16,6 +16,11 @@
*/
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) {
var translate = '';
@ -29,7 +34,9 @@ rcube_webmail.prototype.swipe = {
}
}
if (bw.edge && $(obj).is('tr')) { // Edge does not support transform on <tr>s
// Edge (Trident) 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);
}
else {
@ -41,8 +48,8 @@ rcube_webmail.prototype.swipe = {
if (!props.uid)
return;
var prev_uid = rcmail.env[rcmail.env.task == 'addressbook' ? 'cid' : 'uid'];
rcmail.env[rcmail.env.task == 'addressbook' ? 'cid' : 'uid'] = props.uid;
var prev_uid = rcmail.env[rcmail.env.swipe_selection_id];
rcmail.env[rcmail.env.swipe_selection_id] = props.uid;
var type = null;
if (matches = command.match(/([a-z0-9_-]+)\/([a-z0-9-_]+)/)) {
@ -54,8 +61,7 @@ rcube_webmail.prototype.swipe = {
rcmail.mark_message(command);
}
else if (type == 'compose') {
rcmail.enable_command(command, true);
rcmail.command(command, '', props.obj, props.originalEvent);
rcmail.command(command, '', props.obj, props.originalEvent, true);
}
else if (type == 'select') {
rcmail.env.swipe_list.highlight_row(props.uid, true);
@ -72,7 +78,7 @@ rcube_webmail.prototype.swipe = {
rcmail.enable_command(command, prev_command);
}
rcmail.env[rcmail.env.task == 'addressbook' ? 'cid' : 'uid'] = prev_uid;
rcmail.env[rcmail.env.swipe_selection_id] = prev_uid;
},
select_action: function(direction, obj) {
@ -133,7 +139,7 @@ rcube_webmail.prototype.swipe = {
'command': obj && obj.hasClass('flagged') ? 'mark/unflagged' : 'mark/flagged'
},
'swipe-select': {
'class': (obj && obj.hasClass('selected') ? 'select invert' : 'select all') + ' swipe_active',
'class': (obj && obj.hasClass('selected') ? 'select invert' : 'selection') + ' swipe_active',
'text': obj && obj.hasClass('selected') ? 'swipe.deselect' : 'select',
'command': obj && obj.hasClass('selected') ? 'select/deselect' : 'select/select'
},
@ -174,22 +180,30 @@ rcube_webmail.prototype.swipe = {
'moveevent': 'pointermove',
'endevent': 'pointerup',
'cancelevent': 'pointercancel',
'minmove': 5,
'id': function(e) { return e.pointerId; },
'type': function(e) { return e.pointerType; },
'pos': function(e, x) { return e.originalEvent[ x ? 'pageX' : 'pageY']; },
'clearswipe': function(e) {
rcmail.swipe.position_target(opts[swipedata.axis].target_obj, 0);
opts[swipedata.axis].target_obj.removeClass('swipe-active');
swipedata = {};
rcmail.swipe.active = null;
// reset #swipe-action
$('#swipe-action').removeClass().hide();
$('.swipe-container').attr('class', rcmail.env.swipe_container_class);
$('.swipe-action').attr('class', rcmail.env.swipe_button_class);
$('.swipe-container').attr('class', rcmail.swipe.container_class);
$('.swipe-action').attr('class', rcmail.swipe.button_class);
rcmail.swipe.set_scroll_css();
if (opts.parent_obj)
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 = {};
@ -200,6 +214,7 @@ rcube_webmail.prototype.swipe = {
swipeevents.moveevent = 'touchmove';
swipeevents.endevent = 'touchend';
swipeevents.cancelevent = 'touchcancel';
swipeevents.minmove = 15;
swipeevents.id = function(e) { return e.changedTouches.length == 1 ? e.changedTouches[0].identifier : -1; };
swipeevents.type = function(e) { return 'touch'; };
swipeevents.pos = function(e, x) { return e.originalEvent.targetTouches[0][ x ? 'pageX' : 'pageY']; };
@ -213,6 +228,7 @@ rcube_webmail.prototype.swipe = {
swipedata.y = swipeevents.pos(e, false);
swipedata.id = swipeevents.id(e);
swipedata.scrollable = rcmail.swipe.parent[0].offsetHeight < rcmail.swipe.parent[0].scrollHeight;
swipedata.scrolltop = rcmail.swipe.parent.scrollTop();
if (opts.parent_obj)
opts.parent_obj.off(swipeevents.moveevent, rcube_event.cancel);
@ -231,7 +247,7 @@ rcube_webmail.prototype.swipe = {
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
var min_move = 5; // the minimum amount of pointer movement required to trigger the swipe
var min_move = swipeevents.minmove; // the minimum amount of pointer movement required to trigger the swipe
var temp_axis;
if (opts.vertical && (Math.abs(changeY) > min_move || opts.vertical.target_obj.hasClass('swipe-active'))) {
temp_axis = 'vertical';
@ -249,14 +265,17 @@ rcube_webmail.prototype.swipe = {
// do not interfere with normal list scrolling
if (temp_axis == 'vertical' && rcmail.swipe.parent.scrollTop() != 0) {
if (bw.pointer && swipedata.scrollable)
rcmail.swipe.parent.css('touch-action', 'pan-y');
if (swipedata.scrollable)
rcmail.swipe.set_scroll_css();
if (swipedata.axis)
swipeevents.clearswipe(e);
return;
}
else if (temp_axis == 'horizontal' && !bw.pointer && swipedata.scrolltop != rcmail.swipe.parent.scrollTop()) {
return;
}
// save the axis info
swipedata.axis = temp_axis;
@ -268,8 +287,8 @@ rcube_webmail.prototype.swipe = {
return;
$('#swipe-action').attr('class', temp_axis).data('callback', action.callback);
$('.swipe-container').attr('class', rcmail.env.swipe_container_class + ' ' + direction);
$('.swipe-action').attr('class', rcmail.env.swipe_button_class + ' ' + action.class);
$('.swipe-container').attr('class', rcmail.swipe.container_class + ' ' + direction);
$('.swipe-action').attr('class', rcmail.swipe.button_class + ' ' + action.class);
$('.swipe-label').text(rcmail.gettext(action.text));
if (!opts[swipedata.axis].target_obj.hasClass('swipe-active')) {
@ -285,17 +304,21 @@ rcube_webmail.prototype.swipe = {
if (opts.parent_obj)
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
// do not activate if there is no callback
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) {
$('#swipe-action').addClass(action.class);
$('#swipe-action.horizontal,#swipe-action.vertical > .swipe-container').addClass(action.class);
}
else {
// reset the swipe if the user takes the row back to the start
$('#swipe-action').removeClass(action.class);
$('#swipe-action.horizontal,#swipe-action.vertical > .swipe-container').removeClass(action.class);
$('#swipe-action').data('callback', null);
}
@ -316,25 +339,31 @@ rcube_webmail.prototype.swipe = {
if (swipedata.axis)
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() {
if (window.rcmail && ((bw.touch && !bw.ie) || bw.pointer)) {
rcmail.addEventListener('init', function() {
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';
rcmail.env.swipe_list = rcmail[rcmail.env.swipe_list_name];
var list_container = $(rcmail.env.swipe_list.list).parent();
if (rcmail.env.swipe_list.draggable || !list_container[0].addEventListener)
return;
// 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'))))
);
var swipe_action = $('<div>').attr('id', 'swipe-action').append(rcmail.swipe.element);
rcmail.swipe.parent = list_container;
rcmail.swipe.parent.prepend(swipe_action.hide());
@ -405,27 +434,14 @@ $(document).ready(function() {
rcmail.swipe.init(swipe_config);
// prevent accidental list scroll when swipe active
rcmail.swipe.parent.on('scroll', function() {
if (!bw.pointer) {
if (rcmail.swipe.active)
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');
rcmail.swipe.parent.on('scroll', function() { rcmail.swipe.set_scroll_css(); }).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;
}
});
}
rcmail.env.swipe_list.addEventListener('getselection', function(p) {
if (rcmail.swipe.active && rcmail.env[rcmail.env.swipe_selection_id]) {
p.res = [rcmail.env[rcmail.env.swipe_selection_id]];
return false;
}
});
});
// right/left/down swipe on list
@ -446,7 +462,7 @@ $(document).ready(function() {
'transition': 'translatex',
'action_sytle': function(o) {
return {
'top': o.position().top,
'top': o.position().top + (bw.mz ? rcmail.swipe.parent.scrollTop() : 0),
'left': o.position().left,
'width': o.width() + 'px',
'height': (o.height() - 2) + 'px' // subtract the border

@ -7,7 +7,7 @@
*
* @author Philip Weir
*
* Copyright (C) 2018-2019 Philip Weir
* Copyright (C) Philip Weir
*
* This program is a Roundcube (https://roundcube.net) plugin.
* For more information see README.md.
@ -27,7 +27,7 @@
*/
class swipe extends rcube_plugin
{
public $task = 'mail|addressbook';
public $task = '^((?!login).)*$';
private $menu_file = null;
private $dont_override = array();
private $disabled_actions = array();
@ -35,6 +35,8 @@ class swipe extends rcube_plugin
private $config = array();
private $actions = array(
'messagelist' => array(
'list_name' => 'message_list',
'selection_id' => 'uid',
'vertical' => array(
'checkmail' => array('label' => 'checkmail')
),
@ -52,6 +54,8 @@ class swipe extends rcube_plugin
)
),
'contactlist' => array(
'list_name' => 'contact_list',
'selection_id' => 'cid',
'vertical' => array(),
'horizontal' => array(
'vcard_attachments' => array('label' => 'vcard_attachments.forwardvcard', 'plugin' => true),
@ -59,7 +63,8 @@ class swipe extends rcube_plugin
'delete' => array('label' => 'delete'),
'swipe-select' => array('label' => 'select')
)
)
),
'none' => null
);
private $rcube;
private $list_type;
@ -67,9 +72,19 @@ class swipe extends rcube_plugin
public function init()
{
$this->rcube = rcube::get_instance();
$this->list_type = $this->rcube->task == 'addressbook' ? 'contactlist' : 'messagelist';
$this->add_texts('localization/');
switch ($this->rcube->task) {
case 'addressbook':
$this->list_type = 'contactlist';
break;
case 'mail':
$this->list_type = 'messagelist';
break;
default:
$this->list_type = 'none';
}
$this->add_hook('ready', array($this, 'setup'));
$this->register_action('plugin.swipe.save_settings', array($this, 'save_settings'));
}
@ -85,35 +100,47 @@ class swipe extends rcube_plugin
$this->menu_file = '/' . $this->local_skin_path() . '/includes/menu.html';
$filepath = slashify($this->home) . $this->menu_file;
if (is_file($filepath) && is_readable($filepath)) {
// Allow other plugins to interact with the actions list
$data = rcube::get_instance()->plugins->exec_hook('swipe_actions', array('list_type' => $this->list_type, 'actions' => $this->actions[$this->list_type]));
$this->list_type = $data['list_type'];
$this->actions[$this->list_type] = $data['actions'];
if (empty($this->actions[$this->list_type])) {
// no swipe actions found, disable the plugin
return;
}
$config = $this->config[$this->list_type];
$this->rcube->output->set_env('swipe_actions', array(
'left' => $config['left'],
'right' => $config['right'],
'down' => $config['down']
));
$this->rcube->output->set_env('swipe_list_name', $this->actions[$this->list_type]['list_name']);
$this->rcube->output->set_env('swipe_selection_id', $this->actions[$this->list_type]['selection_id']);
$this->include_stylesheet($this->local_skin_path() . '/swipe.css');
$this->include_script('swipe.js');
$this->rcube->output->add_label('swipe.swipeoptions', 'swipe.markasflagged', 'swipe.markasunflagged', 'swipe.markasread',
'swipe.markasunread', 'refresh', 'moveto', 'reply', 'replyall', 'forward', 'select', 'swipe.deselect', 'compose');
$this->rcube->output->add_handler('swipeoptionslist', array($this, 'options_list'));
}
if ($this->_allowed_action('*')) {
// add swipe actions link to the menu
$this->add_button(array(
'command' => 'plugin.swipe.options',
'type' => 'link',
'class' => 'button swipe disabled',
'classact' => 'button swipe',
'title' => 'swipe.swipeoptions',
'innerclass' => 'inner',
'label' => 'swipe.swipeoptions'
), 'listcontrols');
// add swipe actions popup menu
$html = $this->rcube->output->just_parse("<roundcube:include file=\"$this->menu_file\" skinpath=\"plugins/swipe\" />");
$this->rcube->output->add_footer($html);
if ($this->_allowed_action('*')) {
// add swipe actions link to the menu
$this->add_button(array(
'command' => 'plugin.swipe.options',
'type' => 'link',
'class' => 'button swipe disabled',
'classact' => 'button swipe',
'title' => 'swipe.swipeoptions',
'innerclass' => 'inner',
'label' => 'swipe.swipeoptions'
), 'listcontrols');
// add swipe actions popup menu
$this->rcube->output->add_handler('swipeoptionslist', array($this, 'options_list'));
$html = $this->rcube->output->just_parse("<roundcube:include file=\"$this->menu_file\" skinpath=\"plugins/swipe\" />");
$this->rcube->output->add_footer($html);
}
}
}
@ -124,11 +151,8 @@ class swipe extends rcube_plugin
$args['id'] = 'swipeoptions-' . $args['direction'];
$args['name'] = 'swipe_' . $args['direction'];
// Allow other plugins to interact with the action list
$data = rcube::get_instance()->plugins->exec_hook('swipe_actions_list', array('actions' => $swipe_actions, 'direction' => $args['direction']));
$options = array();
foreach ($data['actions'] as $action => $info) {
foreach ($swipe_actions as $action => $info) {
if (!$this->_allowed_action($args['direction'], $action, $info)) {
continue;
}
@ -138,7 +162,7 @@ class swipe extends rcube_plugin
asort($options);
// don't add none if there are no available actions, JS detects empty lists and hides the option
if (count($options) > 0) {
if (!empty($options)) {
$options = array('none' => $this->gettext('none')) + $options;
}
@ -168,6 +192,10 @@ class swipe extends rcube_plugin
{
$this->_load_config();
// Allow other plugins to interact with the actions list
$data = rcube::get_instance()->plugins->exec_hook('swipe_actions', array('list_type' => $this->list_type, 'actions' => $this->actions[$this->list_type]));
$this->list_type = $data['list_type'];
$save = false;
foreach (array('left', 'right', 'down') as $direction) {
if (($prop = rcube_utils::get_input_value('swipe_' . $direction, rcube_utils::INPUT_POST)) && $this->_allowed_action($direction)) {
@ -189,7 +217,9 @@ class swipe extends rcube_plugin
// initialize internal config
foreach (array_keys($this->actions) as $list) {
$this->config[$list] = array('left' => 'none', 'right' => 'none', 'down' => 'none');
if ($list != 'none') {
$this->config[$list] = array('left' => 'none', 'right' => 'none', 'down' => 'none');
}
}
// get user config
@ -218,10 +248,10 @@ class swipe extends rcube_plugin
in_array('swipe_actions.' . $this->list_type . '.' . $direction, $this->dont_override)) {
$result = false;
}
else if (in_array($action, $this->disabled_actions) || in_array($this->rcube->task . $action, $this->disabled_actions)) {
elseif (in_array($action, $this->disabled_actions) || in_array($this->rcube->task . $action, $this->disabled_actions)) {
$result = false;
}
else if (isset($opts['plugin']) && !in_array($action, $this->laoded_plugins)) {
elseif (isset($opts['plugin']) && !in_array($action, $this->laoded_plugins)) {
// check plugin is enabled
$result = false;
}

Loading…
Cancel
Save