1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 23:02:42 +01:00

Add an Emoji Typeahead

Summary:
This adds a more complete emoji datasource, with a typeahead and autocomplete. It works by pulling in a raw datasource from EmojiOne (I chose Unicode 8, but they have a Unicode 9 datasource as well) and transforming it for speed/need. If we build more robustness or an actual picker into the Remarkup bar, having the additional keywords, etc, might be important. When Unicode 9 support is more prevalent, we should only need to update the single file.

 Tossing up as a proof of concept on engineering direction. Also I can't quite get the autocomplete to complete.

Test Plan: Test UIExamples, Autocomplete, and TypeaheadSource

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin

Maniphest Tasks: T12139

Differential Revision: https://secure.phabricator.com/D17244
This commit is contained in:
Chad Little 2017-01-24 13:00:35 -08:00
parent 61216dc641
commit f930fd2e00
9 changed files with 1792 additions and 9 deletions

View file

@ -540,7 +540,7 @@ return array(
'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9',
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b', 'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '6d86ce8b', 'rsrc/js/phuix/PHUIXAutocomplete.js' => '7c492cd2',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50',
'rsrc/js/phuix/PHUIXFormControl.js' => 'bbece68d', 'rsrc/js/phuix/PHUIXFormControl.js' => 'bbece68d',
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b', 'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
@ -899,7 +899,7 @@ return array(
'phui-workpanel-view-css' => 'a3a63478', 'phui-workpanel-view-css' => 'a3a63478',
'phuix-action-list-view' => 'b5c256b8', 'phuix-action-list-view' => 'b5c256b8',
'phuix-action-view' => 'b3465b9b', 'phuix-action-view' => 'b3465b9b',
'phuix-autocomplete' => '6d86ce8b', 'phuix-autocomplete' => '7c492cd2',
'phuix-dropdown-menu' => '8018ee50', 'phuix-dropdown-menu' => '8018ee50',
'phuix-form-control-view' => 'bbece68d', 'phuix-form-control-view' => 'bbece68d',
'phuix-icon-view' => 'bff6884b', 'phuix-icon-view' => 'bff6884b',
@ -1423,12 +1423,6 @@ return array(
'javelin-typeahead', 'javelin-typeahead',
'javelin-uri', 'javelin-uri',
), ),
'6d86ce8b' => array(
'javelin-install',
'javelin-dom',
'phuix-icon-view',
'phabricator-prefab',
),
'70baed2f' => array( '70baed2f' => array(
'javelin-install', 'javelin-install',
'javelin-dom', 'javelin-dom',
@ -1496,6 +1490,12 @@ return array(
'owners-path-editor', 'owners-path-editor',
'javelin-behavior', 'javelin-behavior',
), ),
'7c492cd2' => array(
'javelin-install',
'javelin-dom',
'phuix-icon-view',
'phabricator-prefab',
),
'7cbe244b' => array( '7cbe244b' => array(
'javelin-install', 'javelin-install',
'javelin-util', 'javelin-util',

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,48 @@
#!/usr/bin/env php
<?php
require_once dirname(dirname(__FILE__)).'/__init_script__.php';
$args = new PhutilArgumentParser($argv);
$args->setTagline(pht('regenerate Emoji data sheets'));
$args->setSynopsis(<<<EOHELP
**emoji**
Rebuild Emoji data sheets.
EOHELP
);
$args->parseStandardArguments();
$args->parse(
array(
array(
'name' => 'force',
'help' => pht('Force regeneration even if sources have not changed.'),
),
));
$root = dirname(phutil_get_library_root('phabricator'));
$path = $root.'/webroot/rsrc/externals/emojione/emoji_strategy.json';
$export_path = $root.'/webroot/rsrc/emoji/manifest.json';
if (Filesystem::pathExists($path)) {
$json = Filesystem::readFile($path);
$emojis = phutil_json_decode($json);
$data = array();
foreach ($emojis as $shortname => $emoji) {
$unicode = $emoji['unicode'];
$codes = explode('-', $unicode);
$hex = '';
foreach ($codes as $code) {
$hex .= phutil_utf8_encode_codepoint(hexdec($code));
}
$data[$shortname] = $hex;
}
$json = new PhutilJSON();
$data = $json->encodeFormatted($data);
Filesystem::writeFile($export_path, $data);
echo pht('Done.')."\n";
} else {
echo pht('Path %s not exist.', $path)."\n";
}

View file

@ -1412,6 +1412,7 @@ phutil_register_library_map(array(
'LiskRawMigrationIterator' => 'infrastructure/storage/lisk/LiskRawMigrationIterator.php', 'LiskRawMigrationIterator' => 'infrastructure/storage/lisk/LiskRawMigrationIterator.php',
'MacroConduitAPIMethod' => 'applications/macro/conduit/MacroConduitAPIMethod.php', 'MacroConduitAPIMethod' => 'applications/macro/conduit/MacroConduitAPIMethod.php',
'MacroCreateMemeConduitAPIMethod' => 'applications/macro/conduit/MacroCreateMemeConduitAPIMethod.php', 'MacroCreateMemeConduitAPIMethod' => 'applications/macro/conduit/MacroCreateMemeConduitAPIMethod.php',
'MacroEmojiExample' => 'applications/uiexample/examples/MacroEmojiExample.php',
'MacroQueryConduitAPIMethod' => 'applications/macro/conduit/MacroQueryConduitAPIMethod.php', 'MacroQueryConduitAPIMethod' => 'applications/macro/conduit/MacroQueryConduitAPIMethod.php',
'ManiphestAssignEmailCommand' => 'applications/maniphest/command/ManiphestAssignEmailCommand.php', 'ManiphestAssignEmailCommand' => 'applications/maniphest/command/ManiphestAssignEmailCommand.php',
'ManiphestAssigneeDatasource' => 'applications/maniphest/typeahead/ManiphestAssigneeDatasource.php', 'ManiphestAssigneeDatasource' => 'applications/maniphest/typeahead/ManiphestAssigneeDatasource.php',
@ -2626,6 +2627,7 @@ phutil_register_library_map(array(
'PhabricatorEmailVarySubjectsSetting' => 'applications/settings/setting/PhabricatorEmailVarySubjectsSetting.php', 'PhabricatorEmailVarySubjectsSetting' => 'applications/settings/setting/PhabricatorEmailVarySubjectsSetting.php',
'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php', 'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php',
'PhabricatorEmbedFileRemarkupRule' => 'applications/files/markup/PhabricatorEmbedFileRemarkupRule.php', 'PhabricatorEmbedFileRemarkupRule' => 'applications/files/markup/PhabricatorEmbedFileRemarkupRule.php',
'PhabricatorEmojiDatasource' => 'applications/macro/typeahead/PhabricatorEmojiDatasource.php',
'PhabricatorEmojiRemarkupRule' => 'applications/macro/markup/PhabricatorEmojiRemarkupRule.php', 'PhabricatorEmojiRemarkupRule' => 'applications/macro/markup/PhabricatorEmojiRemarkupRule.php',
'PhabricatorEmojiTranslation' => 'infrastructure/internationalization/translation/PhabricatorEmojiTranslation.php', 'PhabricatorEmojiTranslation' => 'infrastructure/internationalization/translation/PhabricatorEmojiTranslation.php',
'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php', 'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php',
@ -6242,6 +6244,7 @@ phutil_register_library_map(array(
'LiskRawMigrationIterator' => 'PhutilBufferedIterator', 'LiskRawMigrationIterator' => 'PhutilBufferedIterator',
'MacroConduitAPIMethod' => 'ConduitAPIMethod', 'MacroConduitAPIMethod' => 'ConduitAPIMethod',
'MacroCreateMemeConduitAPIMethod' => 'MacroConduitAPIMethod', 'MacroCreateMemeConduitAPIMethod' => 'MacroConduitAPIMethod',
'MacroEmojiExample' => 'PhabricatorUIExample',
'MacroQueryConduitAPIMethod' => 'MacroConduitAPIMethod', 'MacroQueryConduitAPIMethod' => 'MacroConduitAPIMethod',
'ManiphestAssignEmailCommand' => 'ManiphestEmailCommand', 'ManiphestAssignEmailCommand' => 'ManiphestEmailCommand',
'ManiphestAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'ManiphestAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
@ -7639,6 +7642,7 @@ phutil_register_library_map(array(
'PhabricatorEmailVarySubjectsSetting' => 'PhabricatorSelectSetting', 'PhabricatorEmailVarySubjectsSetting' => 'PhabricatorSelectSetting',
'PhabricatorEmailVerificationController' => 'PhabricatorAuthController', 'PhabricatorEmailVerificationController' => 'PhabricatorAuthController',
'PhabricatorEmbedFileRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorEmbedFileRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'PhabricatorEmojiDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorEmojiRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorEmojiRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorEmojiTranslation' => 'PhutilTranslation', 'PhabricatorEmojiTranslation' => 'PhutilTranslation',
'PhabricatorEmptyQueryException' => 'Exception', 'PhabricatorEmptyQueryException' => 'Exception',

View file

@ -13,6 +13,13 @@ final class PhabricatorEmojiRemarkupRule extends PhutilRemarkupRule {
$text); $text);
} }
public function markupEmojiJSON() {
$root = dirname(phutil_get_library_root('phabricator'));
$json = Filesystem::readFile(
$root.'/resources/emoji/manifest.json');
return $json;
}
public function markupEmoji(array $matches) { public function markupEmoji(array $matches) {
if (!$this->isFlatText($matches[0])) { if (!$this->isFlatText($matches[0])) {
return $matches[0]; return $matches[0];

View file

@ -0,0 +1,45 @@
<?php
final class PhabricatorEmojiDatasource extends PhabricatorTypeaheadDatasource {
public function getPlaceholderText() {
return pht('Type an emoji name...');
}
public function getBrowseTitle() {
return pht('Browse Emojis');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorMacroApplication';
}
public function loadResults() {
$results = $this->buildResults();
return $this->filterResultsAgainstTokens($results);
}
protected function renderSpecialTokens(array $values) {
return $this->renderTokensFromResults($this->buildResults(), $values);
}
private function buildResults() {
$raw_query = $this->getRawQuery();
$data = id(new PhabricatorEmojiRemarkupRule())->markupEmojiJSON();
$emojis = phutil_json_decode($data);
$results = array();
foreach ($emojis as $shortname => $emoji) {
$display_name = $emoji.' '.$shortname;
$result = id(new PhabricatorTypeaheadResult())
->setPHID($shortname)
->setName($display_name)
->setAutocomplete($emoji);
$results[$shortname] = $result;
}
return $results;
}
}

View file

@ -0,0 +1,47 @@
<?php
final class MacroEmojiExample extends PhabricatorUIExample {
public function getName() {
return pht('Emoji Support');
}
public function getDescription() {
return pht('Shiny happy people holding hands');
}
public function renderExample() {
$raw = id(new PhabricatorEmojiRemarkupRule())
->markupEmojiJSON();
$json = phutil_json_decode($raw);
$content = array();
foreach ($json as $shortname => $hex) {
$display_name = ' '.$hex.' '.$shortname;
$content[] = phutil_tag(
'div',
array(
'class' => 'ms grouped',
'style' => 'width: 240px; height: 24px; float: left;',
),
$display_name);
}
$wrap = id(new PHUIObjectBoxView())
->setHeaderText(pht('Emojis'))
->addClass('grouped')
->appendChild($content);
return phutil_tag(
'div',
array(),
array(
$wrap,
));
}
}

View file

@ -55,6 +55,7 @@ final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl {
$root_id = celerity_generate_unique_node_id(); $root_id = celerity_generate_unique_node_id();
$user_datasource = new PhabricatorPeopleDatasource(); $user_datasource = new PhabricatorPeopleDatasource();
$emoji_datasource = new PhabricatorEmojiDatasource();
$proj_datasource = id(new PhabricatorProjectDatasource()) $proj_datasource = id(new PhabricatorProjectDatasource())
->setParameters( ->setParameters(
array( array(
@ -91,6 +92,12 @@ final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl {
'headerText' => pht('Find Project:'), 'headerText' => pht('Find Project:'),
'hintText' => $proj_datasource->getPlaceholderText(), 'hintText' => $proj_datasource->getPlaceholderText(),
), ),
58 => array( // ":"
'datasourceURI' => $emoji_datasource->getDatasourceURI(),
'headerIcon' => 'fa-smile-o',
'headerText' => pht('Find Emoji:'),
'hintText' => $emoji_datasource->getPlaceholderText(),
),
), ),
)); ));
Javelin::initBehavior('phabricator-tooltips', array()); Javelin::initBehavior('phabricator-tooltips', array());

View file

@ -118,7 +118,6 @@ JX.install('PHUIXAutocomplete', {
case '|': // Might be a table cell. case '|': // Might be a table cell.
case '>': // Might be a blockquote. case '>': // Might be a blockquote.
case '!': // Might be a blockquote attribution line. case '!': // Might be a blockquote attribution line.
case ':': // Might be a "NOTE:".
// We'll let these autocomplete. // We'll let these autocomplete.
break; break;
default: default: