From 33a8d845c12a9a6394a5fb8fa8edd851126e19e2 Mon Sep 17 00:00:00 2001 From: Treer Date: Wed, 4 May 2016 23:55:32 +1000 Subject: Refine permissions dialog UI --- Zotlabs/Module/Channel.php | 10 ++++++- Zotlabs/Module/Network.php | 12 +++++++-- include/acl_selectors.php | 27 +++++++++++++++---- view/js/acl.js | 37 ++++++++++++++++++++----- view/theme/redbasic/css/style.css | 57 ++++++++++++++++++++++++++++++++++----- view/tpl/acl_selector.tpl | 27 +++++++++++++++---- 6 files changed, 145 insertions(+), 25 deletions(-) diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 36f13e775..ee7140475 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -126,13 +126,21 @@ function get($update = 0, $load = false) { if($perms['post_wall']) { + // I'm trying to make two points in this description text - warn about finality of wall + // post permissions, and try to clear up confusion that these permissions set who is + // *shown* the post, istead of who is able to see the post, i.e. make it clear that clicking + // the "Show" button on a group does not post it to the feed of people in that group, it + // mearly allows those people to view the post if they are viewing/following this channel. + $aclDesc = t('Post permissions cannot be changed after a post is sent.
These permissions set who is allowed to view the post.'); + $aclContextHelpCmd = ''; + $x = array( 'is_owner' => $is_owner, 'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(\App::$profile['profile_uid'],'system','use_browser_location')))) ? true : false), 'default_location' => (($is_owner) ? \App::$profile['channel_location'] : ''), 'nickname' => \App::$profile['channel_address'], 'lockstate' => (((strlen(\App::$profile['channel_allow_cid'])) || (strlen(\App::$profile['channel_allow_gid'])) || (strlen(\App::$profile['channel_deny_cid'])) || (strlen(\App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'), - 'acl' => (($is_owner) ? populate_acl($channel_acl,true,((\App::$profile['channel_r_stream'] & PERMS_PUBLIC) ? t('Public') : '')) : ''), + 'acl' => (($is_owner) ? populate_acl($channel_acl,true,((\App::$profile['channel_r_stream'] & PERMS_PUBLIC) ? t('Public') : ''), $aclDesc, $aclContextHelpCmd) : ''), 'showacl' => (($is_owner) ? 'yes' : ''), 'bang' => '', 'visitor' => (($is_owner || $observer) ? true : false), diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 77353da05..a6b36ad3c 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -154,6 +154,14 @@ class Network extends \Zotlabs\Web\Controller { } nav_set_selected('network'); + + // I'm trying to make two points in this description text - warn about finality of wall + // post permissions, and try to clear up confusion that these permissions set who is + // *shown* the post, istead of who is able to see the post, i.e. make it clear that clicking + // the "Show" button on a group does not post it to the feed of people in that group, it + // mearly allows those people to view the post if they are viewing/following this channel. + $aclDesc = t('Post permissions cannot be changed after a post is sent.
These permissions set who is allowed to view the post.'); + $aclContextHelpCmd = ''; $channel_acl = array( 'allow_cid' => $channel['channel_allow_cid'], @@ -161,7 +169,7 @@ class Network extends \Zotlabs\Web\Controller { 'deny_cid' => $channel['channel_deny_cid'], 'deny_gid' => $channel['channel_deny_gid'] ); - + $private_editing = ((($group || $cid) && (! intval($_GET['pf']))) ? true : false); $x = array( @@ -170,7 +178,7 @@ class Network extends \Zotlabs\Web\Controller { 'default_location' => $channel['channel_location'], 'nickname' => $channel['channel_address'], 'lockstate' => (($private_editing || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), - 'acl' => populate_acl((($private_editing) ? $def_acl : $channel_acl), true, (($channel['channel_r_stream'] & PERMS_PUBLIC) ? t('Public') : '')), + 'acl' => populate_acl((($private_editing) ? $def_acl : $channel_acl), true, (($channel['channel_r_stream'] & PERMS_PUBLIC) ? t('Public') : ''), $aclDesc, $aclContextHelpCmd), 'bang' => (($private_editing) ? '!' : ''), 'visitor' => true, 'profile_uid' => local_channel(), diff --git a/include/acl_selectors.php b/include/acl_selectors.php index 92f9436a2..c22055848 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -210,12 +210,24 @@ function fixacl(&$item) { $item = str_replace(array('<','>'),array('',''),$item); } -function populate_acl($defaults = null,$show_jotnets = true, $showall = '') { +/** +* Builds a modal dialog for editing permissions, using acl_selector.tpl as the template. +* +* @param array $default Optional access control list for the initial state of the dialog. +* @param boolean $show_jotnets Whether plugins for federated networks should be included in the permissions dialog +* @param string $showall_caption An optional caption to describe the scope of an unrestricted post. e.g. "Public" +* @param string $dialog_description Optional message to include at the top of the dialog. E.g. "Warning: Post permissions cannot be changed once sent". +* @param string $context_help Allows the dialog to present a context sensitive help icon. E.g. "photos/permissions" +* @param boolean $readonly Not implemented yet. When implemented, the dialog will use acl_readonly.tpl instead, so that permissions may be viewed for posts that can no longer have their permissions changed. +* +* @return string html modal dialog build from acl_selector.tpl +*/ +function populate_acl($defaults = null,$show_jotnets = true, $showall_caption = '', $dialog_description = '', $context_help = '', $readonly = false) { $allow_cid = $allow_gid = $deny_cid = $deny_gid = false; - if(! $showall) - $showall = t('Visible to your default audience'); + if(! $showall_caption) + $showall_caption = t('Visible to your default audience'); if(is_array($defaults)) { $allow_cid = ((strlen($defaults['allow_cid'])) @@ -239,9 +251,12 @@ function populate_acl($defaults = null,$show_jotnets = true, $showall = '') { $tpl = get_markup_template("acl_selector.tpl"); $o = replace_macros($tpl, array( - '$showall' => $showall, + '$showall' => $showall_caption, + '$showlimited' => t("Limit access:"), + '$showlimitedDesc' => t('Select "Show" to allow access. "Don\'t show" lets you override and limit the scope of "Show".'), '$show' => t("Show"), '$hide' => t("Don't show"), + '$search' => t("Search"), '$allowcid' => json_encode($allow_cid), '$allowgid' => json_encode($allow_gid), '$denycid' => json_encode($deny_cid), @@ -249,7 +264,9 @@ function populate_acl($defaults = null,$show_jotnets = true, $showall = '') { '$jnetModalTitle' => t('Other networks and post services'), '$jotnets' => $jotnets, '$aclModalTitle' => t('Permissions'), - '$aclModalDismiss' => t('Close') + '$aclModalDesc' => $dialog_description, + '$aclModalDismiss' => t('Close'), + '$helpUrl' => (($context_help == '') ? '' : (z_root() . '/help?f=&cmd=' . $context_help)) )); return $o; diff --git a/view/js/acl.js b/view/js/acl.js index be215fc91..162ada764 100644 --- a/view/js/acl.js +++ b/view/js/acl.js @@ -14,8 +14,9 @@ function ACL(backend_url, preset) { that.nw = 4; //items per row. should be calulated from #acl-list.width that.list_content = $("#acl-list-content"); - that.item_tpl = unescape($(".acl-list-item[rel=acl-template]").html()); - that.showall = $("#acl-showall"); + that.item_tpl = unescape($(".acl-list-item[rel=acl-template]").html()); + that.showall = $("#acl-showall"); + that.showlimited = $("#acl-showlimited"); // set the initial ACL lists in case the enclosing form gets submitted before the ajax loader completes. that.on_submit(); @@ -26,6 +27,7 @@ function ACL(backend_url, preset) { $(document).ready(function() { that.showall.click(that.on_showall); + that.showlimited.click(that.on_showlimited); $(document).on('click','.acl-button-show',that.on_button_show); $(document).on('click','.acl-button-hide',that.on_button_hide); $("#acl-search").keypress(that.on_search); @@ -71,7 +73,8 @@ ACL.prototype.on_search = function(event) { }; ACL.prototype.on_showall = function(event) { - event.preventDefault(); + + // preventDefault() isn't called here as we want state changes from update_view() to be applied to the radiobutton event.stopPropagation(); if (that.showall.hasClass("btn-warning")) { @@ -87,9 +90,17 @@ ACL.prototype.on_showall = function(event) { that.update_view(); that.on_submit(); - return false; + return true; // return true so that state changes from update_view() will be applied }; +ACL.prototype.on_showlimited = function(event) { + // Prevent the radiobutton from being selected, as the showlimited radiobutton + // option is selected only by selecting show or hide options on channels or groups. + event.preventDefault(); + event.stopPropagation(); + return false; +} + ACL.prototype.on_selectall = function(event) { event.preventDefault(); event.stopPropagation(); @@ -188,18 +199,32 @@ ACL.prototype.set_deny = function(itemid) { that.update_view(); }; +ACL.prototype.update_radiobuttons = function(isPublic) { + + that.showall.prop('checked', isPublic); + that.showlimited.prop('checked', !isPublic); + that.showlimited.prop('disabled', isPublic); +}; + ACL.prototype.update_view = function() { if (that.allow_gid.length === 0 && that.allow_cid.length === 0 && that.deny_gid.length === 0 && that.deny_cid.length === 0) { + // btn-warning indicates that the permissions are public, it was chosen because + // that.showall used to be a normal button, which btn-warning is a bootstrap style for. that.showall.removeClass("btn-default").addClass("btn-warning"); + that.update_radiobuttons(true); + /* jot acl */ - $('#jot-perms-icon').removeClass('fa-lock').addClass('fa-unlock'); + $('#jot-perms-icon, #dialog-perms-icon').removeClass('fa-lock').addClass('fa-unlock'); $('#jot-public').show(); $('.profile-jot-net input').attr('disabled', false); + } else { that.showall.removeClass("btn-warning").addClass("btn-default"); + that.update_radiobuttons(false); + /* jot acl */ - $('#jot-perms-icon').removeClass('fa-unlock').addClass('fa-lock'); + $('#jot-perms-icon, #dialog-perms-icon').removeClass('fa-unlock').addClass('fa-lock'); $('#jot-public').hide(); $('.profile-jot-net input').attr('disabled', 'disabled'); diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css index 58f216029..4dd3488e5 100644 --- a/view/theme/redbasic/css/style.css +++ b/view/theme/redbasic/css/style.css @@ -912,19 +912,43 @@ a.rconnect:hover, a.rateme:hover, div.rateme:hover { clear: both; } +.modal-header .contextual-help-tool { + /* Mostly duplicating ".modal-header .close" and ".close" layout settings from bootstrap */ + float: right; + font-size: 21px; + padding: 0; + margin-top: -4px; + margin-right: 15px; + line-height: 1; +} + #acl-search { - margin-top: 20px; - padding: 8px; + padding: 4px; border: 1px solid #ccc; - width: 100%; + width: 90%; /* fallback if browser does not support calc() */ + width: calc(100% - 10px); + margin: 0px 0px 10px 10px; } #acl-search::-webkit-input-placeholder { - font-family: FontAwesome; + /* non-fontawesome fonts set a fallback for text parts of the placeholder*/ + font-family: FontAwesome, sans-serif, arial, freesans; } #acl-search::-moz-placeholder { - font-family: FontAwesome; + /* non-fontawesome fonts set a fallback for text parts of the placeholder*/ + font-family: FontAwesome, sans-serif, arial, freesans; +} + +#acl-dialog-description { + font-size: 90%; + color: #888; +} +#acl-showlimited-description { + font-size: 90%; + color: #888; + margin-left: 10px; + margin-bottom: 4px; } #acl-list { @@ -933,11 +957,11 @@ a.rconnect:hover, a.rateme:hover, div.rateme:hover { overflow: auto; clear: both; min-height: 62px; - margin-top: 20px; padding: 10px 10px 0px 0px; -webkit-border-radius: $radiuspx ; -moz-border-radius: $radiuspx; border-radius: $radiuspx; + background-color: rgb(238,238,238); } #jotnets-wrapper, #jotnets-collapse { @@ -957,6 +981,7 @@ a.rconnect:hover, a.rateme:hover, div.rateme:hover { -webkit-border-radius: $radiuspx ; -moz-border-radius: $radiuspx; border-radius: $radiuspx; + background-color: white; } .acl-list-item.grouphide { @@ -995,6 +1020,26 @@ a.rconnect:hover, a.rateme:hover, div.rateme:hover { margin-left: 5px; } +#acl-showlimited-caption, +#acl-showall-caption { + font-size: 115%; +} + +#acl-radiowrapper-showall { + margin-bottom: 20px; +} +#acl-radiowrapper-showlimited { + margin-bottom: 0; +} + +#acl-showall + i { + font-size: 140%; +} + +#acl-showall-caption { + margin-left: 0.35em; +} + .contact-block-content { margin-top: 10px; } diff --git a/view/tpl/acl_selector.tpl b/view/tpl/acl_selector.tpl index e57fdba12..49d90cd3e 100755 --- a/view/tpl/acl_selector.tpl +++ b/view/tpl/acl_selector.tpl @@ -3,9 +3,13 @@