Support hash and space as valid tag separators

https://xetown.com/questions/1728094

- 해시(#) 문자와 공백도 태그 구분자로 사용할 수 있도록 지원
- 해시는 기본 지원하며, 공백은 기본 OFF
- tag 모듈 설정에서 커스터마이징 가능
- document 모듈 이외의 자료에서 태그 기능 구현한 경우 적용되지 않을 수 있음
This commit is contained in:
Kijin Sung 2022-12-16 01:02:42 +09:00
parent e821955129
commit 38900d4b2d
8 changed files with 242 additions and 47 deletions

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<module>
<permissions />
<actions>
<action name="dispTagAdminConfig" type="view" admin_index="true" menu_name="tag" />
<action name="procTagAdminInsertConfig" type="controller" />
</actions>
<menus>
<menu name="tag" type="all">
<title xml:lang="ko">태그</title>
<title xml:lang="en">Tag</title>
<title xml:lang="zh-CN">标签</title>
<title xml:lang="zh-TW">標籤</title>
<title xml:lang="jp">タグ</title>
<title xml:lang="vi">Tag</title>
<title xml:lang="es">Etiqueta</title>
<title xml:lang="ru">Теги</title>
<title xml:lang="tr">Etiket</title>
</menu>
</menus>
</module>

8
modules/tag/lang/en.php Normal file
View file

@ -0,0 +1,8 @@
<?php
$lang->tag_default_config = 'Default Config';
$lang->tag_separators = 'Tag Separators';
$lang->tag_separator_comma = 'comma(foo, bar)';
$lang->tag_separator_hash = 'hash(#foo #bar)';
$lang->tag_separator_space = 'space';
$lang->tag_separator_help = 'If you select more than one type of separator, all of them will be recognized. For example, &quot;#foo,bar Rhymix&quot;';

8
modules/tag/lang/ko.php Normal file
View file

@ -0,0 +1,8 @@
<?php
$lang->tag_default_config = '태그 기본 설정';
$lang->tag_separators = '태그 구분 방법';
$lang->tag_separator_comma = '쉼표(foo, bar)';
$lang->tag_separator_hash = '해시(#foo #bar)';
$lang->tag_separator_space = '공백';
$lang->tag_separator_help = '두 가지 이상 선택할 경우 모두 인식합니다. 예: &quot;#foo,bar Rhymix&quot; 입력시 해시태그와 쉼표, 공백 모두 구분자로 인식할 수 있습니다.';

View file

@ -7,6 +7,34 @@
*/ */
class tagAdminController extends tag class tagAdminController extends tag
{ {
/**
* Save admin config.
*/
public function procTagAdminInsertConfig()
{
$config = new stdClass;
$vars = Context::getRequestVars();
$config->separators = [];
foreach ($vars->separators ?? [] as $val)
{
if (in_array($val, ['comma', 'hash', 'space']))
{
$config->separators[] = $val;
}
}
$oModuleController = ModuleController::getInstance();
$output = $oModuleController->insertModuleConfig($this->module, $config);
if (!$output->toBool())
{
return $output;
}
$this->setMessage('success_registed');
$this->setRedirectUrl(Context::get('success_return_url'));
}
/** /**
* @brief Delete all tags for a particular module * @brief Delete all tags for a particular module
*/ */

View file

@ -0,0 +1,13 @@
<?php
class tagAdminView extends tag
{
public function dispTagAdminConfig()
{
$config = ModuleModel::getModuleConfig($this->module) ?: new stdClass;
Context::set('tag_config', $config);
$this->setTemplatePath($this->module_path . 'tpl');
$this->setTemplateFile('config');
}
}

View file

@ -8,78 +8,78 @@
class tagController extends tag class tagController extends tag
{ {
/** /**
* @brief Initialization * Parse tags.
*/
function init()
{
}
/**
* @brief , (Comma) to clean up the tags attached to the trigger
*/ */
function triggerArrangeTag(&$obj) function triggerArrangeTag(&$obj)
{ {
if(!$obj->tags) return; if (empty($obj->tags))
// tags by variable
$arranged_tag_list = array();
$tag_list = explode(',', $obj->tags);
foreach($tag_list as $tag)
{ {
$tag = utf8_trim(utf8_normalize_spaces($tag)); return;
if($tag)
{
$arranged_tag_list[$tag] = $tag;
}
} }
if(!count($arranged_tag_list))
$tag_list = tagModel::splitString($obj->tags ?? '');
if (count($tag_list))
{ {
$obj->tags = null; $obj->tags = implode(', ', $tag_list);
} }
else else
{ {
$obj->tags = implode(',', $arranged_tag_list); $obj->tags = null;
} }
} }
/** /**
* @brief Input trigger tag * Replace all tags belonging to a document with a new list of tags.
* Enter a Tag to delete that article and then re-enter all the tags using a method *
* @param object $obj
* @return BaseObject
*/ */
function triggerInsertTag(&$obj) function triggerInsertTag(&$obj)
{ {
$module_srl = $obj->module_srl; if (!$obj->document_srl)
$document_srl = $obj->document_srl; {
$tags = $obj->tags; return new BaseObject;
if(!$document_srl) return; }
// Remove all tags that article
// Remove all existing tags.
$output = $this->triggerDeleteTag($obj); $output = $this->triggerDeleteTag($obj);
if(!$output->toBool()) return $output; if(!$output->toBool())
{
return $output;
}
// Re-enter the tag // Re-enter the tag
$args = new stdClass(); $args = new stdClass();
$args->module_srl = $module_srl; $args->module_srl = $obj->module_srl;
$args->document_srl = $document_srl; $args->document_srl = $obj->document_srl;
$tag_list = explode(',', $tags); $tag_list = tagModel::splitString($obj->tags ?? '');
foreach($tag_list as $tag) foreach ($tag_list as $tag)
{ {
$args->tag = utf8_trim(utf8_normalize_spaces($tag)); $args->tag = $tag;
if(!$args->tag) continue;
$output = executeQuery('tag.insertTag', $args); $output = executeQuery('tag.insertTag', $args);
if(!$output->toBool()) return $output; if(!$output->toBool())
{
return $output;
}
} }
} }
/** /**
* @brief Delete the tag trigger a specific article * Delete all tags belonging to a document.
* document_srl delete tag belongs to *
* @param object $obj
* @return BaseObject
*/ */
function triggerDeleteTag(&$obj) function triggerDeleteTag(&$obj)
{ {
$document_srl = $obj->document_srl; if (!$obj->document_srl)
if(!$document_srl) return; {
return new BaseObject;
}
$args = new stdClass(); $args = new stdClass();
$args->document_srl = $document_srl; $args->document_srl = $obj->document_srl;
return executeQuery('tag.deleteTag', $args); return executeQuery('tag.deleteTag', $args);
} }
@ -88,11 +88,13 @@ class tagController extends tag
*/ */
function triggerDeleteModuleTags(&$obj) function triggerDeleteModuleTags(&$obj)
{ {
$module_srl = $obj->module_srl; if (!$obj->module_srl)
if(!$module_srl) return; {
return;
}
$oTagController = getAdminController('tag'); $oTagController = getAdminController('tag');
return $oTagController->deleteModuleTags($module_srl); return $oTagController->deleteModuleTags($obj->module_srl);
} }
function triggerMoveDocument($obj) function triggerMoveDocument($obj)

View file

@ -8,12 +8,77 @@
class tagModel extends tag class tagModel extends tag
{ {
/** /**
* @brief Initialization * Separator regexp cache
*/ */
function init() protected static $_separator_list = null;
protected static $_separator_regexp = null;
/**
* Generate and cache separator list and regexp.
*/
protected static function _generateSeparatorConfig()
{ {
$config = ModuleModel::getModuleConfig('tag');
if (isset($config->separators) && count($config->separators))
{
self::$_separator_list = $config->separators;
}
else
{
self::$_separator_list = ['comma', 'hash'];
}
$regexp = '/[';
$regexp_map = [
'comma' => ',',
'hash' => '#',
'space' => '\\s',
];
foreach (self::$_separator_list as $separator)
{
$regexp .= $regexp_map[$separator];
}
$regexp .= ']+/';
self::$_separator_regexp = $regexp;
} }
/**
* Split a string of tags into an array.
*
* @param string $str
* @return array
*/
public static function splitString(string $str): array
{
if (!isset(self::$_separator_list))
{
self::_generateSeparatorConfig();
}
// Clean up the input string.
$str = trim(utf8_normalize_spaces(utf8_clean($str)));
if ($str === '')
{
return [];
}
// Split the input string and collect non-empty fragments.
$fragments = preg_split(self::$_separator_regexp, $str, -1, PREG_SPLIT_NO_EMPTY);
$tags = [];
foreach ($fragments as $fragment)
{
$fragment = trim($fragment);
if ($fragment !== '')
{
$tags[strtolower($fragment)] = $fragment;
}
}
// Return a list of valid fragments with no duplicates.
return array_values(array_unique($tags));
}
/** /**
* @brief Imported Tag List * @brief Imported Tag List
* Many of the specified module in order to extract the number of tags * Many of the specified module in order to extract the number of tags

View file

@ -0,0 +1,50 @@
<config autoescape="on" />
<div class="x_page-header">
<h1>{$lang->tag}</h1>
</div>
<ul class="x_nav x_nav-tabs">
<li class="x_active"|cond="$act === 'dispTagAdminConfig'">
<a href="{getUrl('', 'module', 'admin', 'act', 'dispTagAdminConfig')}">{$lang->tag_default_config}</a>
</li>
</ul>
<form class="x_form-horizontal" action="./" method="post" enctype="multipart/form-data" id="eventpayment">
<input type="hidden" name="module" value="tag" />
<input type="hidden" name="act" value="procTagAdminInsertConfig" />
<input type="hidden" name="success_return_url" value="{getUrl('', 'module', 'admin', 'act', 'dispTagAdminConfig')}" />
<input type="hidden" name="xe_validator_id" value="modules/tag/tpl/config/1" />
<div class="message {$XE_VALIDATOR_MESSAGE_TYPE ?? ''}" cond="!empty($XE_VALIDATOR_MESSAGE) && $XE_VALIDATOR_ID == 'modules/tag/tpl/config/1'">
<p>{$XE_VALIDATOR_MESSAGE}</p>
</div>
<section class="section">
<div class="x_control-group">
<label class="x_control-label">{$lang->tag_separators}</label>
<div class="x_controls">
<label class="x_inline" for="separators1">
<input type="checkbox" name="separators[]" id="separators1" value="comma" checked="checked"|cond="empty($tag_config->separators) || in_array('comma', $tag_config->separators)" />
{$lang->tag_separator_comma}
</label>
<label class="x_inline" for="separators2">
<input type="checkbox" name="separators[]" id="separators2" value="hash" checked="checked"|cond="empty($tag_config->separators) || in_array('hash', $tag_config->separators)" />
{$lang->tag_separator_hash}
</label>
<label class="x_inline" for="separators3">
<input type="checkbox" name="separators[]" id="separators3" value="space" checked="checked"|cond="!empty($tag_config->separators) && in_array('space', $tag_config->separators)" />
{$lang->tag_separator_space}
</label>
<p class="x_help-block">
{$lang->tag_separator_help}
</p>
</div>
</div>
</section>
<div class="btnArea x_clearfix">
<button type="submit" class="x_btn x_btn-primary x_pull-right">{$lang->cmd_registration}</button>
</div>
</form>