Merge pull request #9125 from MrPetovan/bug/8999-fix-new-pm

Fix new private message recipient input
This commit is contained in:
Michael Vogel 2020-09-03 21:45:31 +02:00 committed by GitHub
commit 560746eb3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 106 additions and 197 deletions

View file

@ -28,6 +28,7 @@ use Friendica\Core\Logger;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Session; use Friendica\Core\Session;
use Friendica\Core\Theme;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Model\Contact; use Friendica\Model\Contact;
@ -354,6 +355,13 @@ function conv_get_blocklist()
*/ */
function conversation(App $a, array $items, $mode, $update, $preview = false, $order = 'commented', $uid = 0) function conversation(App $a, array $items, $mode, $update, $preview = false, $order = 'commented', $uid = 0)
{ {
$page = DI::page();
$page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
$page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
$ssl_state = (local_user() ? true : false); $ssl_state = (local_user() ? true : false);
$profile_owner = 0; $profile_owner = 0;

View file

@ -74,7 +74,7 @@ function message_post(App $a)
$replyto = !empty($_REQUEST['replyto']) ? Strings::escapeTags(trim($_REQUEST['replyto'])) : ''; $replyto = !empty($_REQUEST['replyto']) ? Strings::escapeTags(trim($_REQUEST['replyto'])) : '';
$subject = !empty($_REQUEST['subject']) ? Strings::escapeTags(trim($_REQUEST['subject'])) : ''; $subject = !empty($_REQUEST['subject']) ? Strings::escapeTags(trim($_REQUEST['subject'])) : '';
$body = !empty($_REQUEST['body']) ? Strings::escapeHtml(trim($_REQUEST['body'])) : ''; $body = !empty($_REQUEST['body']) ? Strings::escapeHtml(trim($_REQUEST['body'])) : '';
$recipient = !empty($_REQUEST['messageto']) ? intval($_REQUEST['messageto']) : 0; $recipient = !empty($_REQUEST['recipient']) ? intval($_REQUEST['recipient']) : 0;
$ret = Mail::send($recipient, $body, $subject, $replyto); $ret = Mail::send($recipient, $body, $subject, $replyto);
$norecip = false; $norecip = false;
@ -215,50 +215,14 @@ function message_content(App $a)
'$linkurl' => DI::l10n()->t('Please enter a link URL:') '$linkurl' => DI::l10n()->t('Please enter a link URL:')
]); ]);
$preselect = isset($a->argv[2]) ? [$a->argv[2]] : []; $recipientId = $a->argv[2] ?? null;
$prename = $preurl = $preid = ''; $select = ACL::getMessageContactSelectHTML($recipientId);
if ($preselect) {
$r = q("SELECT `name`, `url`, `id` FROM `contact` WHERE `uid` = %d AND `id` = %d LIMIT 1",
intval(local_user()),
intval($a->argv[2])
);
if (!DBA::isResult($r)) {
$r = q("SELECT `name`, `url`, `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' LIMIT 1",
intval(local_user()),
DBA::escape(Strings::normaliseLink(base64_decode($a->argv[2])))
);
}
if (!DBA::isResult($r)) {
$r = q("SELECT `name`, `url`, `id` FROM `contact` WHERE `uid` = %d AND `addr` = '%s' LIMIT 1",
intval(local_user()),
DBA::escape(base64_decode($a->argv[2]))
);
}
if (DBA::isResult($r)) {
$prename = $r[0]['name'];
$preid = $r[0]['id'];
$preselect = [$preid];
} else {
$preselect = [];
}
}
$prefill = $preselect ? $prename : '';
// the ugly select box
$select = ACL::getMessageContactSelectHTML('messageto', 'message-to-select', $preselect, 4, 10);
$tpl = Renderer::getMarkupTemplate('prv_message.tpl'); $tpl = Renderer::getMarkupTemplate('prv_message.tpl');
$o .= Renderer::replaceMacros($tpl, [ $o .= Renderer::replaceMacros($tpl, [
'$header' => DI::l10n()->t('Send Private Message'), '$header' => DI::l10n()->t('Send Private Message'),
'$to' => DI::l10n()->t('To:'), '$to' => DI::l10n()->t('To:'),
'$showinputs' => 'true',
'$prefill' => $prefill,
'$preid' => $preid,
'$subject' => DI::l10n()->t('Subject:'), '$subject' => DI::l10n()->t('Subject:'),
'$subjtxt' => $_REQUEST['subject'] ?? '', '$subjtxt' => $_REQUEST['subject'] ?? '',
'$text' => $_REQUEST['body'] ?? '', '$text' => $_REQUEST['body'] ?? '',
@ -413,7 +377,7 @@ function message_content(App $a)
$seen = $message['seen']; $seen = $message['seen'];
} }
$select = $message['name'] . '<input type="hidden" name="messageto" value="' . $contact_id . '" />'; $select = $message['name'] . '<input type="hidden" name="recipient" value="' . $contact_id . '" />';
$parent = '<input type="hidden" name="replyto" value="' . $message['parent-uri'] . '" />'; $parent = '<input type="hidden" name="replyto" value="' . $message['parent-uri'] . '" />';
$tpl = Renderer::getMarkupTemplate('mail_display.tpl'); $tpl = Renderer::getMarkupTemplate('mail_display.tpl');
@ -429,7 +393,6 @@ function message_content(App $a)
// reply // reply
'$header' => DI::l10n()->t('Send Reply'), '$header' => DI::l10n()->t('Send Reply'),
'$to' => DI::l10n()->t('To:'), '$to' => DI::l10n()->t('To:'),
'$showinputs' => '',
'$subject' => DI::l10n()->t('Subject:'), '$subject' => DI::l10n()->t('Subject:'),
'$subjtxt' => $message['title'], '$subjtxt' => $message['title'],
'$readonly' => ' readonly="readonly" style="background: #BBBBBB;" ', '$readonly' => ' readonly="readonly" style="background: #BBBBBB;" ',

View file

@ -33,75 +33,52 @@ use Friendica\Model\Group;
class ACL class ACL
{ {
/** /**
* Returns a select input tag with all the contact of the local user * Returns a select input tag for private message recipient
* *
* @param string $selname Name attribute of the select input tag * @param int $selected Existing recipien contact ID
* @param string $selclass Class attribute of the select input tag
* @param array $preselected Contact IDs that should be already selected
* @param int $size Length of the select box
* @param int $tabindex Select input tag tabindex attribute
* @return string * @return string
* @throws \Exception * @throws \Exception
*/ */
public static function getMessageContactSelectHTML($selname, $selclass, array $preselected = [], $size = 4, $tabindex = null) public static function getMessageContactSelectHTML(int $selected = null)
{ {
$a = DI::app();
$o = ''; $o = '';
$page = DI::page();
$page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
$page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
// When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector // When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector
// to one recipient. By default our selector allows multiple selects amongst all contacts. // to one recipient. By default our selector allows multiple selects amongst all contacts.
$sql_extra = sprintf(" AND `rel` = %d ", intval(Contact::FRIEND)); $condition = [
$sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ", Protocol::DFRN, Protocol::DIASPORA); 'uid' => local_user(),
'self' => false,
'blocked' => false,
'pending' => false,
'archive' => false,
'deleted' => false,
'rel' => [Contact::FOLLOWER, Contact::SHARING, Contact::FRIEND],
'network' => Protocol::FEDERATED,
];
$tabindex_attr = !empty($tabindex) ? ' tabindex="' . intval($tabindex) . '"' : ''; $contacts = Contact::selectToArray(
['id', 'name', 'addr', 'micro'],
$hidepreselected = ''; DBA::mergeConditions($condition, ["`notify` != ''"])
if ($preselected) {
$sql_extra .= " AND `id` IN (" . implode(",", $preselected) . ")";
$hidepreselected = ' style="display: none;"';
}
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\"$tabindex_attr$hidepreselected>\r\n";
$stmt = DBA::p("SELECT `id`, `name`, `url`, `network` FROM `contact`
WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND NOT `deleted` AND `notify` != ''
$sql_extra
ORDER BY `name` ASC ", intval(local_user())
); );
$contacts = DBA::toArray($stmt);
$arr = ['contact' => $contacts, 'entry' => $o]; $arr = ['contact' => $contacts, 'entry' => $o];
// e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow' Hook::callAll(DI::module()->getName() . '_pre_recipient', $arr);
Hook::callAll(DI::module()->getName() . '_pre_' . $selname, $arr);
$receiverlist = []; $tpl = Renderer::getMarkupTemplate('acl/message_recipient.tpl');
$o = Renderer::replaceMacros($tpl, [
'$contacts' => $contacts,
'$selected' => $selected,
]);
if (DBA::isResult($contacts)) { Hook::callAll(DI::module()->getName() . '_post_recipient', $o);
foreach ($contacts as $contact) {
if (in_array($contact['id'], $preselected)) {
$selected = ' selected="selected"';
} else {
$selected = '';
}
$trimmed = Protocol::formatMention($contact['url'], $contact['name']);
$receiverlist[] = $trimmed;
$o .= "<option value=\"{$contact['id']}\"$selected title=\"{$contact['name']}|{$contact['url']}\" >$trimmed</option>\r\n";
}
}
$o .= '</select>' . PHP_EOL;
if ($preselected) {
$o .= implode(', ', $receiverlist);
}
Hook::callAll(DI::module()->getName() . '_post_' . $selname, $o);
return $o; return $o;
} }
@ -303,7 +280,7 @@ class ACL
'emailcc' => $form_prefix ? $form_prefix . '[emailcc]' : 'emailcc', 'emailcc' => $form_prefix ? $form_prefix . '[emailcc]' : 'emailcc',
]; ];
$tpl = Renderer::getMarkupTemplate('acl_selector.tpl'); $tpl = Renderer::getMarkupTemplate('acl/full_selector.tpl');
$o = Renderer::replaceMacros($tpl, [ $o = Renderer::replaceMacros($tpl, [
'$public_title' => DI::l10n()->t('Public'), '$public_title' => DI::l10n()->t('Public'),
'$public_desc' => DI::l10n()->t('This content will be shown to all your followers and can be seen in the community pages and by anyone with its link.'), '$public_desc' => DI::l10n()->t('This content will be shown to all your followers and can be seen in the community pages and by anyone with its link.'),

View file

@ -32,6 +32,7 @@ use Friendica\Core\ACL;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Theme;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
@ -259,9 +260,12 @@ class Contact extends BaseModule
$rel = Strings::escapeTags(trim($_GET['rel'] ?? '')); $rel = Strings::escapeTags(trim($_GET['rel'] ?? ''));
$group = Strings::escapeTags(trim($_GET['group'] ?? '')); $group = Strings::escapeTags(trim($_GET['group'] ?? ''));
if (empty(DI::page()['aside'])) { $page = DI::page();
DI::page()['aside'] = '';
} $page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
$page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
$page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
$contact = null; $contact = null;
// @TODO: Replace with parameter from router // @TODO: Replace with parameter from router

View file

@ -155,7 +155,7 @@
acl.initialize(); acl.initialize();
let suggestionTemplate = function (item) { let suggestionTemplate = function (item) {
return '<div><img src="' + item.micro + '" alt="" style="float: left; width: auto; height: 2.8em; margin-right: 0.5em;"> <strong>' + item.name + '</strong><br /><em>' + item.addr + '</em></div>'; return '<div><img src="' + item.micro + '" alt="" style="float: left; width: auto; height: 2.8em; margin-right: 0.5em;"><p style="margin-left: 3.3em;"><strong>' + item.name + '</strong><br /><em>' + item.addr + '</em></p></div>';
}; };
$acl_allow_input.tagsinput({ $acl_allow_input.tagsinput({

View file

@ -0,0 +1,54 @@
<select name="recipient" class="form-control input-lg" id="recipient">
{{foreach $contacts as $contact}}
<option value="{{$contact.id}}"{{if $contact.id == $selected}} selected{{/if}}>{{$contact.name}}</option>
{{/foreach}}
</select>
<script type="text/javascript">
$(function() {
let $recipient_input = $('[name="recipient"]');
let acl = new Bloodhound({
local: {{$contacts|@json_encode nofilter}},
identify: function(obj) { return obj.id.toString(); },
datumTokenizer: Bloodhound.tokenizers.obj.whitespace(['name', 'addr']),
queryTokenizer: Bloodhound.tokenizers.whitespace,
sorter: function (itemA, itemB) {
if (itemA.name === itemB.name) {
return 0;
} else if (itemA.name > itemB.name) {
return 1;
} else {
return -1;
}
},
});
acl.initialize();
let suggestionTemplate = function (item) {
return '<div><img src="' + item.micro + '" alt="" style="float: left; width: auto; height: 2.8em; margin-right: 0.5em;"><p style="margin-left: 3.3em;"><strong>' + item.name + '</strong><br /><em>' + item.addr + '</em></p></div>';
};
$recipient_input.tagsinput({
confirmKeys: [13, 44],
freeInput: false,
tagClass: 'label label-info',
itemValue: function (item) { return item.id.toString(); },
itemText: 'name',
itemThumb: 'micro',
itemTitle: function(item) {
return item.addr;
},
typeaheadjs: {
name: 'contacts',
displayKey: 'name',
templates: {
suggestion: suggestionTemplate
},
source: acl.ttAdapter()
}
});
// Import existing ACL into the tags input fields.
$recipient_input.tagsinput('add', acl.get({{$selected}})[0]);
});
</script>

View file

@ -1,8 +0,0 @@
<script>
$(document).ready(function() {
$("#recip").name_autocomplete(baseurl + '/search/acl', 'm', false, function(data) {
$("#recip-complete").val(data.id);
});
});
</script>

View file

@ -3228,9 +3228,6 @@ div.jGrowl div.info {
width:100px; width:100px;
} }
#recip {
}
.autocomplete-w1 { background: #ffffff no-repeat bottom right; position:absolute; top:0px; left:0px; margin:6px 0 0 6px; /* IE6 fix: */ _background:none; _margin:1px 0 0 0; } .autocomplete-w1 { background: #ffffff no-repeat bottom right; position:absolute; top:0px; left:0px; margin:6px 0 0 6px; /* IE6 fix: */ _background:none; _margin:1px 0 0 0; }
.autocomplete { color:#000; border:1px solid #999; background:#FFF; cursor:default; text-align:left; max-height:350px; overflow:auto; margin:-6px 6px 6px -6px; /* IE6 specific: */ _height:350px; _margin:0; _overflow-x:hidden; } .autocomplete { color:#000; border:1px solid #999; background:#FFF; cursor:default; text-align:left; max-height:350px; overflow:auto; margin:-6px 6px 6px -6px; /* IE6 specific: */ _height:350px; _margin:0; _overflow-x:hidden; }
.autocomplete .selected { background:#F0F0F0; } .autocomplete .selected { background:#F0F0F0; }

View file

@ -1,40 +0,0 @@
<h3>{{$header}}</h3>
<div id="prvmail-wrapper" >
<form id="prvmail-form" action="message" method="post" >
{{$parent nofilter}}
<div id="prvmail-to-label">{{$to}}</div>
{{if $showinputs}}
<input type="text" id="recip" name="messagerecip" value="{{$prefill}}" maxlength="255" size="64" tabindex="10" />
<input type="hidden" id="recip-complete" name="messageto" value="{{$preid}}">
{{else}}
{{$select nofilter}}
{{/if}}
<div id="prvmail-subject-label">{{$subject}}</div>
<input type="text" size="64" maxlength="255" id="prvmail-subject" name="subject" value="{{$subjtxt}}" {{$readonly}} tabindex="11" />
<div id="prvmail-message-label">{{$yourmessage}}</div>
<textarea rows="8" cols="72" class="prvmail-text" id="prvmail-text" name="body" tabindex="12">{{$text}}</textarea>
<div id="prvmail-submit-wrapper" >
<input type="submit" id="prvmail-submit" name="submit" value="{{$submit}}" tabindex="13" />
<div id="prvmail-upload-wrapper" >
<div id="prvmail-upload" class="icon border camera" title="{{$upload}}" ></div>
</div>
<div id="prvmail-link-wrapper" >
<div id="prvmail-link" class="icon border link" title="{{$insert}}" onclick="jotGetLink();" ></div>
</div>
<div id="prvmail-rotator-wrapper" >
<img id="prvmail-rotator" src="images/rotator.gif" alt="{{$wait}}" title="{{$wait}}" style="display: none;" />
</div>
</div>
<div id="prvmail-end"></div>
</form>
</div>

View file

@ -2,21 +2,12 @@
<div id="prvmail-wrapper"> <div id="prvmail-wrapper">
<form id="prvmail-form" action="message" method="post" > <form id="prvmail-form" action="message" method="post" >
{{* Disable the header. We will see if we will need it
<h3>{{$header}}</h3>
*}}
{{$parent nofilter}} {{$parent nofilter}}
{{* The To: form-group which contains the message recipient *}} {{* The To: form-group which contains the message recipient *}}
<div id="prvmail-to-label" class="form-group"> <div id="prvmail-to-label" class="form-group">
<label for="recip">{{$to}}</label><br> <label for="recipient">{{$to}}</label><br>
{{if $showinputs}}
<input type="text" id="recip" class="form-control" name="messagerecip" value="{{$prefill}}" tabindex="10" {{if $prefill}}disabled{{else}}aria-required="true"{{/if}} />
<input type="hidden" id="recip-complete" name="messageto" value="{{$preid}}">
{{else}}
{{$select nofilter}} {{$select nofilter}}
{{/if}}
</div> </div>
{{* The subject input field *}} {{* The subject input field *}}

View file

@ -1,37 +0,0 @@
<h3>{{$header}}</h3>
<div id="prvmail-wrapper" >
<form id="prvmail-form" action="message" method="post" >
{{$parent nofilter}}
<div id="prvmail-to-label">{{$to}}</div>
{{if $showinputs}}
<input type="text" id="recip" name="messagerecip" value="{{$prefill}}" maxlength="255" size="64" tabindex="10" />
<input type="hidden" id="recip-complete" name="messageto" value="{{$preid}}">
{{else}}
{{$select nofilter}}
{{/if}}
<div id="prvmail-subject-label">{{$subject}}</div>
<input type="text" size="64" maxlength="255" id="prvmail-subject" name="subject" value="{{$subjtxt}}" {{$readonly}} tabindex="11" />
<div id="prvmail-message-label">{{$yourmessage}}</div>
<textarea rows="20" cols="72" class="prvmail-text" id="prvmail-text" name="body" tabindex="12">{{$text}}</textarea>
<div id="prvmail-submit-wrapper" >
<input type="submit" id="prvmail-submit" name="submit" value="{{$submit}}" tabindex="13" />
<div id="prvmail-upload-wrapper" >
<div id="prvmail-upload" class="icon border camera" title="{{$upload}}" ></div>
</div>
<div id="prvmail-link-wrapper" >
<div id="prvmail-link" class="icon border link" title="{{$insert}}" onclick="jotGetLink();" ></div>
</div>
<div id="prvmail-rotator-wrapper" >
<img id="prvmail-rotator" src="images/rotator.gif" alt="{{$wait}}" title="{{$wait}}" style="display: none;" />
</div>
</div>
<div id="prvmail-end"></div>
</form>
</div>