Add suggest menu for user mentions in text editor

This commit is contained in:
Frederic Guillot
2016-11-27 15:44:45 -05:00
parent 04ff67e26b
commit d8b0423d15
21 changed files with 454 additions and 30 deletions

View File

@@ -4,6 +4,7 @@ namespace Kanboard\Controller;
use Kanboard\Filter\UserNameFilter;
use Kanboard\Formatter\UserAutoCompleteFormatter;
use Kanboard\Formatter\UserMentionFormatter;
use Kanboard\Model\UserModel;
/**
@@ -37,7 +38,12 @@ class UserAjaxController extends BaseController
$project_id = $this->request->getStringParam('project_id');
$query = $this->request->getStringParam('q');
$users = $this->projectPermissionModel->findUsernames($project_id, $query);
$this->response->json($users);
$this->response->json(
UserMentionFormatter::getInstance($this->container)
->withUsers($users)
->format()
);
}
/**

View File

@@ -12,6 +12,7 @@ use Pimple\Container;
*
* @property \Kanboard\Helper\AppHelper $app
* @property \Kanboard\Helper\AssetHelper $asset
* @property \Kanboard\Helper\AvatarHelper $avatar
* @property \Kanboard\Helper\BoardHelper $board
* @property \Kanboard\Helper\CalendarHelper $calendar
* @property \Kanboard\Helper\DateHelper $dt

View File

@@ -4,7 +4,6 @@ namespace Kanboard\Formatter;
use Kanboard\Core\Base;
use PicoDb\Table;
use Pimple\Container;
/**
* Class BaseFormatter
@@ -22,19 +21,6 @@ abstract class BaseFormatter extends Base
*/
protected $query;
/**
* Get object instance
*
* @static
* @access public
* @param Container $container
* @return static
*/
public static function getInstance(Container $container)
{
return new static($container);
}
/**
* Set query
*

View File

@@ -2,8 +2,6 @@
namespace Kanboard\Formatter;
use Kanboard\Core\Filter\FormatterInterface;
/**
* Common class to handle calendar events
*
@@ -34,7 +32,7 @@ abstract class BaseTaskCalendarFormatter extends BaseFormatter
* @access public
* @param string $start_column Column name for the start date
* @param string $end_column Column name for the end date
* @return FormatterInterface
* @return $this
*/
public function setColumns($start_column, $end_column = '')
{

View File

@@ -0,0 +1,60 @@
<?php
namespace Kanboard\Formatter;
/**
* Class UserMentionFormatter
*
* @package Kanboard\Formatter
* @author Frederic Guillot
*/
class UserMentionFormatter extends BaseFormatter
{
protected $users = array();
/**
* Set users
*
* @param array $users
* @return $this
*/
public function withUsers(array $users) {
$this->users = $users;
return $this;
}
/**
* Apply formatter
*
* @access public
* @return array
*/
public function format()
{
$result = array();
foreach ($this->users as $user) {
$html = $this->helper->avatar->small(
$user['id'],
$user['username'],
$user['name'],
$user['email'],
$user['avatar_path'],
'avatar-inline'
);
$html .= ' '.$this->helper->text->e($user['username']);
if (! empty($user['name'])) {
$html .= ' <small>'.$this->helper->text->e($user['name']).'</small>';
}
$result[] = array(
'value' => $user['username'],
'html' => $html,
);
}
return $result;
}
}

View File

@@ -204,6 +204,10 @@ class FormHelper extends Base
'placeholder' => t('Write your text in Markdown'),
);
if (isset($values['project_id'])) {
$params['mentionUrl'] = $this->helper->url->to('UserAjaxController', 'mention', array('project_id' => $values['project_id']));
}
$html = '<div class="js-text-editor" data-params=\''.json_encode($params, JSON_HEX_APOS).'\'></div>';
$html .= $this->errorList($errors, $name);

View File

@@ -62,17 +62,33 @@ class ProjectPermissionModel extends Base
->withFilter(new ProjectUserRoleProjectFilter($project_id))
->withFilter(new ProjectUserRoleUsernameFilter($input))
->getQuery()
->findAllByColumn('username');
->columns(
UserModel::TABLE.'.id',
UserModel::TABLE.'.username',
UserModel::TABLE.'.name',
UserModel::TABLE.'.email',
UserModel::TABLE.'.avatar_path'
)
->findAll();
$groupMembers = $this->projectGroupRoleQuery
->withFilter(new ProjectGroupRoleProjectFilter($project_id))
->withFilter(new ProjectGroupRoleUsernameFilter($input))
->getQuery()
->findAllByColumn('username');
->columns(
UserModel::TABLE.'.id',
UserModel::TABLE.'.username',
UserModel::TABLE.'.name',
UserModel::TABLE.'.email',
UserModel::TABLE.'.avatar_path'
)
->findAll();
$members = array_unique(array_merge($userMembers, $groupMembers));
$userMembers = array_column_index_unique($userMembers, 'username');
$groupMembers = array_column_index_unique($groupMembers, 'username');
$members = array_merge($userMembers, $groupMembers);
sort($members);
ksort($members);
return $members;
}

View File

@@ -52,6 +52,37 @@ function array_column_index(array &$input, $column)
return $result;
}
/**
* Create indexed array from a list of dict with unique values
*
* $input = [
* ['k1' => 1, 'k2' => 2], ['k1' => 3, 'k2' => 4], ['k1' => 1, 'k2' => 5]
* ]
*
* array_column_index_unique($input, 'k1') will returns:
*
* [
* 1 => ['k1' => 1, 'k2' => 2],
* 3 => ['k1' => 3, 'k2' => 4],
* ]
*
* @param array $input
* @param string $column
* @return array
*/
function array_column_index_unique(array &$input, $column)
{
$result = array();
foreach ($input as &$row) {
if (isset($row[$column]) && ! isset($result[$row[$column]])) {
$result[$row[$column]] = $row;
}
}
return $result;
}
/**
* Sum all values from a single column in the input array
*