'read',
'channelType' => 'translation',
'contentType' => 'markdown',
'format' => 'react',
'debug' => [],
'studioId' => null,
'lang' => 'zh-Hans',
'footnote' => false,
'paragraph' => false,
'origin' => true,
'translation' => true,
];
/**
* Create a new command instance.
* string $mode 'read' | 'edit'
* string $format 'react' | 'text' | 'tex' | 'unity'
*
* @return void
*/
public function __construct(array $param, $channelInfo, string $mode, string $format = 'react', ?string $studioId = null, $debug = [], $lang = 'zh-Hans')
{
$this->param = $param;
foreach ($channelInfo as $channel) {
if ($channel && isset($channel->uid)) {
$this->channel_id[] = $channel->uid;
} else {
Log::error('template render init error invalid channel');
}
}
$this->channelInfo = $channelInfo;
$this->mode = $mode;
$this->format = $format;
$this->studioId = $studioId;
$this->debug = $debug;
$this->glossaryKey = 'glossary';
if (count($this->channel_id) > 0) {
$channelId = $this->channel_id[0];
if (Str::isUuid($channelId)) {
$lang = Channel::where('uid', $channelId)->value('lang');
}
}
if (! empty($lang)) {
$this->lang = $lang;
$this->langFamily = explode('-', $lang)[0];
}
}
public function options($options = [])
{
foreach ($options as $key => $value) {
$this->options[$key] = $value;
}
}
public function glossaryKey()
{
return $this->glossaryKey;
}
/**
* TODO 设置默认语言。在渲染某些内容的时候需要语言信息
*/
public function setLang($lang)
{
$this->lang = $lang;
$this->langFamily = explode('-', $lang)[0];
}
private function info($message, $debug)
{
if (in_array($debug, $this->debug)) {
Log::info($message);
}
}
private function error($message, $debug)
{
if (in_array($debug, $this->debug)) {
Log::error($message);
}
}
public function render($tpl_name)
{
switch ($tpl_name) {
case 'term':
// 术语
$result = $this->render_term();
break;
case 'note':
$result = $this->render_note();
break;
case 'sent':
$result = $this->render_sent();
break;
case 'quote':
$result = $this->render_quote();
break;
case 'ql':
$result = $this->render_quote_link();
break;
case 'exercise':
$result = $this->render_exercise();
break;
case 'article':
$result = $this->render_article();
break;
case 'nissaya':
$result = $this->render_nissaya();
break;
case 'mermaid':
$result = $this->render_mermaid();
break;
case 'qa':
$result = $this->render_qa();
break;
case 'v':
$result = $this->render_video();
break;
case 'g':
$result = $this->render_grammar_lookup();
break;
case 'ref':
$result = $this->render_ref();
break;
case 'dict-pref':
$result = $this->render_dict_pref();
break;
case 'ai':
$result = $this->render_ai();
break;
case 'para':
$result = $this->render_para();
break;
case 'category':
$result = $this->render_category();
break;
case 'quality':
// 质量标签模版:{{quality|pending}}
$result = $this->render_quality();
break;
default:
if (mb_substr($tpl_name, 0, 4, 'UTF-8') === 'Tpl:') {
$result = $this->render_tpl($tpl_name);
} else {
$result = [
'props' => base64_encode(\json_encode([])),
'html' => '',
'tag' => 'span',
'tpl' => 'unknown',
];
}
break;
}
return $result;
}
public function render_tpl($name)
{
$article = app(ArticleService::class)->getRawByTitle($name);
$content = $article->content;
if (count($this->param) > 0) {
$m = new \Mustache_Engine([
'entity_flags' => ENT_QUOTES,
'escape' => function ($value) {
return $value;
},
]);
$content = $m->render($content, $this->param);
}
$output = [];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode(['content' => $content])),
'html' => $content,
'tag' => 'span',
'tpl' => 'tpl',
];
break;
default:
$output = $content;
break;
}
return $output;
}
public function render_para()
{
$props = [];
$props['id'] = $this->get_param($this->param, 'id', 1);
$props['title'] = $this->get_param($this->param, 'title', 2);
$props['style'] = $this->get_param($this->param, 'style', 3);
$output = [];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => $props['title'],
'tag' => 'span',
'tpl' => 'para',
];
break;
default:
$output = $props['title'];
break;
}
return $output;
}
public function render_category()
{
$props = [];
$props['name'] = $this->get_param($this->param, 'name', 1);
$output = [];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => $props['name'],
'tag' => 'span',
'tpl' => 'para',
];
break;
default:
$output = $props['name'];
break;
}
return $output;
}
/**
* 渲染质量标签模版:{{quality|pending}}
*
* 合法的取值只有四个:featured | standard | draft | pending
* 非法取值统一回退为 pending,避免渲染出未知样式。
*/
public function render_quality()
{
// 默认值为 pending,同时支持命名参数 {{quality|value=featured}}
$value = $this->get_param($this->param, 'value', 1, 'pending');
// 校验取值是否合法,不合法则回退到默认值
$allowed = ['featured', 'standard', 'draft', 'pending'];
if (! in_array($value, $allowed, true)) {
$value = 'pending';
}
$props = ['value' => $value];
$output = [];
switch ($this->format) {
case 'react':
// 前端通过 props 解析,使用 antd Tag 按取值渲染不同颜色
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => $value,
'tag' => 'span',
'tpl' => 'quality',
];
break;
case 'html':
// 静态 html 输出,class 包含固定前缀 tag-quality 和具体取值
$output = "{$value}";
break;
default:
// text / tex / simple 等纯文本格式直接输出取值
$output = $value;
break;
}
return $output;
}
public function getTermProps($word, $tag = null, $channel = null)
{
if ($channel && ! empty($channel)) {
$channelId = $channel;
} else {
if (count($this->channel_id) > 0) {
$channelId = $this->channel_id[0];
} else {
$channelId = null;
}
}
if (count($this->channelInfo) === 0) {
if (! empty($channel)) {
$channelInfo = Channel::where('uid', $channel)->first();
if (! $channelInfo) {
unset($channelInfo);
}
}
if (! isset($channelInfo)) {
Log::warning('channel is null');
$output = [
'word' => $word,
'innerHtml' => '',
];
return $output;
}
} else {
$channelInfo = $this->channelInfo[0];
}
if (Str::isUuid($channelId)) {
$lang = Channel::where('uid', $channelId)->value('lang');
if (! empty($lang)) {
$langFamily = explode('-', $lang)[0];
} else {
$langFamily = 'zh';
}
$this->info("term:{$word} 先查属于这个channel 的", 'term');
$this->info('channel id'.$channelId, 'term');
$table = DhammaTerm::where('word', $word)
->where('channal', $channelId);
if ($tag && ! empty($tag)) {
$table = $table->where('tag', $tag);
}
$tplParam = $table->orderBy('updated_at', 'desc')
->first();
$studioId = $channelInfo->owner_uid;
} else {
$tplParam = false;
$lang = '';
$langFamily = '';
$studioId = $this->studioId;
}
if (! $tplParam) {
if (Str::isUuid($studioId)) {
/**
* 没有,再查这个studio的
* 按照语言过滤
* 完全匹配的优先
* 语族匹配也行
*/
$this->info('没有-再查这个studio的', 'term');
$table = DhammaTerm::where('word', $word);
if (! empty($tag)) {
$table = $table->where('tag', $tag);
}
$termsInStudio = $table->where('owner', $channelInfo->owner_uid)
->orderBy('updated_at', 'desc')
->get();
if (count($termsInStudio) > 0) {
$list = [];
foreach ($termsInStudio as $key => $term) {
if (empty($term->channal)) {
if ($term->language === $lang) {
$list[$term->guid] = 2;
} elseif (strpos($term->language, $langFamily) !== false) {
$list[$term->guid] = 1;
}
}
}
if (count($list) > 0) {
arsort($list);
foreach ($list as $key => $one) {
foreach ($termsInStudio as $term) {
if ($term->guid === $key) {
$tplParam = $term;
break;
}
}
break;
}
}
}
}
}
if (! $tplParam) {
$this->info('没有,再查社区', 'term');
$community_channel = ChannelApi::getSysChannel('_community_term_zh-hans_');
$table = DhammaTerm::where('word', $word);
if (! empty($tag)) {
$table = $table->where('tag', $tag);
}
$tplParam = $table->where('channal', $community_channel)
->first();
if ($tplParam) {
$isCommunity = true;
} else {
$this->info('查社区没有', 'term');
}
}
$output = [
'word' => $word,
'parentChannelId' => $channelId,
'parentStudioId' => $channelInfo ? $channelInfo->owner_uid : null,
];
$innerString = $output['word'];
if ($tplParam) {
$output['id'] = $tplParam->guid;
$output['meaning'] = $tplParam->meaning;
$output['channel'] = $tplParam->channal;
if (! empty($tplParam->note)) {
$mdRender = new MdRender(['format' => $this->format]);
$output['note'] = $mdRender->convert($tplParam->note, $this->channel_id);
}
if (isset($isCommunity)) {
$output['isCommunity'] = true;
}
$innerString = "{$output['meaning']}({$output['word']})";
if (! empty($tplParam->other_meaning)) {
$output['meaning2'] = $tplParam->other_meaning;
}
}
$output['innerHtml'] = $innerString;
return $output;
}
private function render_term()
{
$word = $this->get_param($this->param, 'word', 1);
if (str_contains($word, '@')) {
[$wordHead, $tag] = explode('@', $word);
}
if (str_contains($word, '#')) {
[$wordHead, $display] = explode('#', $word);
}
$props = $this->getTermProps($wordHead ?? $word, $tag ?? '');
if (isset($display)) {
$props['meaning'] = $display;
}
$output = $props['word'];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => $props['innerHtml'],
'tag' => 'span',
'tpl' => 'term',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'term',
];
break;
case 'html':
$no = isset($props['id']) ? '' : 'term_invalid';
$id = isset($props['id']) ? $props['id'] : '';
$output = ' $GLOBALS['note_sn'],
'trigger' => '',
'content' => $content,
];
}
break;
default:
$output = $props['meaning'] ?? $props['word'];
break;
}
return $output;
}
private function render_note()
{
$note = $this->get_param($this->param, 'text', 1);
$trigger = $this->get_param($this->param, 'trigger', 2, '');
$props = ['note' => $note];
$innerString = '';
if (! empty($trigger)) {
$props['trigger'] = $trigger;
$innerString = $props['trigger'];
}
if ($this->format === 'unity') {
$props['note'] = MdRender::render(
$props['note'],
$this->channel_id,
null,
'read',
'translation',
'markdown',
'unity'
);
}
$output = $note;
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => $innerString,
'tag' => 'span',
'tpl' => 'note',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'note',
];
break;
case 'html':
if (isset($GLOBALS['note_sn'])) {
$GLOBALS['note_sn']++;
} else {
$GLOBALS['note_sn'] = 1;
$GLOBALS['note'] = [];
}
$noteContent = MdRender::render(
$props['note'],
$this->channel_id,
null,
'read',
'translation',
'markdown',
'html'
);
$GLOBALS['note'][] = [
'sn' => $GLOBALS['note_sn'],
'trigger' => $trigger,
'content' => $noteContent,
];
$link = "";
if (empty($trigger)) {
$output = $link.'['.$GLOBALS['note_sn'].']';
} else {
$output = $link.$trigger.'';
}
$output = "
{$noteContent}";
break;
case 'text':
$output = $trigger;
break;
case 'tex':
$output = $trigger;
break;
case 'simple':
$output = '';
break;
case 'markdown':
if (isset($GLOBALS['note_sn'])) {
$GLOBALS['note_sn']++;
} else {
$GLOBALS['note_sn'] = 1;
$GLOBALS['note'] = [];
}
$content = MdRender::render(
$props['note'],
$this->channel_id,
null,
'read',
'translation',
'markdown',
'markdown'
);
$output = '[^'.$GLOBALS['note_sn'].']';
$GLOBALS['note'][] = [
'sn' => $GLOBALS['note_sn'],
'trigger' => $trigger,
'content' => $content,
];
// $output = ''.$content.'';
break;
default:
$output = '';
break;
}
return $output;
}
private function render_nissaya()
{
$pali = $this->get_param($this->param, 'pali', 1);
$meaning = $this->get_param($this->param, 'meaning', 2);
$innerString = '';
$props = [
'pali' => $pali,
'meaning' => explode('=', $meaning),
'lang' => $this->lang,
];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => $innerString,
'tag' => 'span',
'tpl' => 'nissaya',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'nissaya',
];
break;
case 'prompt':
$output = Tools::MyToRm($pali).':'.end($props['meaning']);
break;
default:
$output = $pali.'၊'.$meaning;
break;
}
return $output;
}
private function render_exercise()
{
$id = $this->get_param($this->param, 'id', 1);
$title = $this->get_param($this->param, 'title', 1);
$props = [
'id' => $id,
'title' => $title,
'channel' => $this->channel_id[0],
];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'tag' => 'span',
'tpl' => 'exercise',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'exercise',
];
break;
case 'text':
$output = $title;
break;
case 'tex':
$output = $title;
break;
case 'simple':
$output = $title;
break;
default:
$output = '';
break;
}
return $output;
}
private function render_article()
{
$type = $this->get_param($this->param, 'type', 1);
$id = $this->get_param($this->param, 'id', 2);
$title = $this->get_param($this->param, 'title', 3);
$channel = $this->get_param($this->param, 'channel', 4);
$style = $this->get_param($this->param, 'style', 5);
$book = $this->get_param($this->param, 'book', 6);
$paragraphs = $this->get_param($this->param, 'paragraphs', 7);
$anthology = $this->get_param($this->param, 'anthology', 8);
if ($type === 'chapter' && empty($id)) {
$book = (int) $book;
$paragraphs = (int) $paragraphs;
$id = "{$book}-{$paragraphs}";
}
$props = [
'type' => $type,
'id' => $id,
'style' => $style,
];
if (! empty($channel)) {
$props['channel'] = $channel;
}
if (! empty($title)) {
$props['title'] = $title;
}
if (! empty($book)) {
$props['book'] = $book;
}
if (! empty($paragraphs)) {
$props['paragraphs'] = $paragraphs;
}
if (! empty($anthology)) {
$props['anthology'] = $anthology;
}
if (is_array($this->channel_id)) {
$props['parentChannels'] = $this->channel_id;
}
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'text' => $title,
'tag' => 'span',
'tpl' => 'article',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'article',
];
break;
case 'text':
$output = $title;
break;
case 'tex':
$output = $title;
break;
case 'simple':
$output = $title;
break;
default:
$output = '';
break;
}
return $output;
}
private function render_quote()
{
$paraId = $this->get_param($this->param, 'para', 1);
$channelId = $this->channel_id[0];
$props = Cache::remember(
"/quote/{$channelId}/{$paraId}",
config('mint.cache.expire'),
function () use ($paraId, $channelId) {
$para = \explode('-', $paraId);
$output = [
'paraId' => $paraId,
'channel' => $channelId,
'innerString' => $paraId,
];
if (count($para) < 2) {
return $output;
}
$PaliText = PaliText::where('book', $para[0])
->where('paragraph', $para[1])
->select(['toc', 'path'])
->first();
if ($PaliText) {
$output['pali'] = $PaliText->toc;
$output['paliPath'] = \json_decode((string) $PaliText->path, true);
$output['innerString'] = $PaliText->toc;
}
return $output;
}
);
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => $props['innerString'],
'tag' => 'span',
'tpl' => 'quote',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'quote',
];
break;
case 'text':
$output = $props['innerString'];
break;
case 'tex':
$output = $props['innerString'];
break;
case 'simple':
$output = $props['innerString'];
break;
default:
$output = $props['innerString'];
break;
}
return $output;
}
private function render_quote_link()
{
$type = $this->get_param($this->param, 'type', 1);
$title = $this->get_param($this->param, 'title', 6, '');
$bookName = $this->get_param($this->param, 'bookname', 2, '');
$volume = $this->get_param($this->param, 'volume', 3);
$page = $this->get_param($this->param, 'page', 4, '');
$style = $this->get_param($this->param, 'style', 5, 'modal');
$book = $this->get_param($this->param, 'book', 7, false);
$para = $this->get_param($this->param, 'para', 8, false);
$props = [
'type' => $type,
'style' => $style,
'found' => true,
];
if (! empty($bookName) && $volume !== '' && ! empty($page)) {
$props['bookName'] = $bookName;
$props['volume'] = (int) $volume;
$props['page'] = $page;
$props['found'] = true;
} elseif ($book && $para) {
/**
* 没有指定书名,根据book para 查询
*/
if ($type === 'c') {
// 按照章节名称显示
$path = PaliTextApi::getChapterPath($book, $para);
if ($path) {
$path = json_decode($path, true);
}
if ($path && is_array($path) && count($path) > 2) {
$props['bookName'] = strtolower($path[0]['title']);
$props['chapter'] = strtolower(end($path)['title']);
$props['found'] = true;
} else {
$props['found'] = false;
}
} else {
$pageInfo = $this->pageInfoByPara($type, $book, $para);
if ($pageInfo['found']) {
$props['bookName'] = $pageInfo['bookName'];
$props['volume'] = $pageInfo['volume'];
$props['page'] = $pageInfo['page'];
$props['found'] = true;
} else {
$props['found'] = false;
}
}
} elseif ($title) {
// 没有书号用title查询
// $tmpTitle = explode('။',$title);
for ($i = mb_strlen($title, 'UTF-8'); $i > 0; $i--) {
$mTitle = mb_substr($title, 0, $i);
$has = array_search($mTitle, array_column(BookTitle::my(), 'title2'));
if ($has !== false) {
$tmpBookTitle = $mTitle;
$tmpBookPage = mb_substr($title, $i);
$tmpBookPage = $this->mb_trim($tmpBookPage, '၊။');
break;
}
}
if (isset($tmpBookTitle)) {
// $tmpBookTitle = $tmpTitle[0];
// $tmpBookPage = $tmpTitle[1];
$tmpBookPage = (int) str_replace(
['၁', '၂', '၃', '၄', '၅', '၆', '၇', '၈', '၉', '၀'],
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
$tmpBookPage
);
$found_key = array_search($tmpBookTitle, array_column(BookTitle::my(), 'title2'));
if ($found_key !== false) {
$props['bookName'] = BookTitle::my()[$found_key]['bookname'];
$props['volume'] = BookTitle::my()[$found_key]['volume'];
$props['page'] = $tmpBookPage;
if (! empty($props['bookName'])) {
$found_title = array_search($props['bookName'], array_column(BookTitle::my(), 'bookname'));
if ($found_title === false) {
$props['found'] = false;
}
}
} else {
// 没找到,返回术语和页码
$props['found'] = false;
$props['bookName'] = $tmpBookTitle;
$props['page'] = $tmpBookPage;
$props['volume'] = 0;
}
}
} else {
$props['found'] = false;
}
if ($book && $para) {
$props['book'] = $book;
$props['para'] = $para;
}
if ($title) {
$props['title'] = $title;
}
$text = '';
if (isset($props['bookName'])) {
$searchField = '';
switch ($type) {
case 'm':
$searchField = 'm_title';
break;
case 'p':
$searchField = 'p_title';
break;
}
$found_title = array_search($props['bookName'], array_column(BookTitle::get(), $searchField));
if ($found_title === false) {
$props['found'] = false;
}
$term = $this->getTermProps($props['bookName'], ':quote:');
$props['term'] = $term;
if (isset($term['id'])) {
$props['bookNameLocal'] = $term['meaning'];
$text .= $term['meaning'];
} else {
$text .= $bookName;
}
}
if (isset($props['volume']) && isset($props['page'])) {
$text .= " {$volume}.{$page}";
}
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'tag' => 'span',
'tpl' => 'quote-link',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'quote-link',
];
break;
default:
$output = $text;
break;
}
return $output;
}
private function pageInfoByPara($type, $book, $para)
{
$output = [];
$pageInfo = PageNumber::where('type', strtoupper($type))
->where('book', $book)
->where('paragraph', '<=', $para)
->orderBy('paragraph', 'desc')
->first();
if ($pageInfo) {
foreach (BookTitle::get() as $value) {
if ($value['id'] === $pageInfo->pcd_book_id) {
switch (strtoupper($type)) {
case 'M':
$key = 'm_title';
break;
case 'P':
$key = 'p_title';
break;
case 'V':
$key = 'v_title';
break;
default:
$key = 'term';
break;
}
$output['bookName'] = $value[$key];
break;
}
}
$output['volume'] = $pageInfo->volume;
$output['page'] = $pageInfo->page;
$output['found'] = true;
} else {
$output['found'] = false;
}
return $output;
}
private function render_sent()
{
$sid = $this->get_param($this->param, 'id', 1);
$channel = $this->get_param($this->param, 'channel', 2);
$show = $this->get_param($this->param, 'text', 2, 'both');
if (! empty($channel)) {
$channels = explode(',', $channel);
} else {
$channels = $this->channel_id;
}
$sentInfo = explode('@', trim($sid));
$sentId = $sentInfo[0];
if (isset($sentInfo[1])) {
$channels = [$sentInfo[1]];
}
$Sent = new CorpusController;
$props = $Sent->getSentTpl(
$sentId,
$channels,
$this->mode,
true,
$this->format
);
if (! $props) {
$props['error'] = '句子模版渲染错误。句子参数个数不符。应该是四个。';
Log::error('句子模版渲染错误。句子参数个数不符。应该是四个。');
}
if ($this->mode === 'read') {
$tpl = 'sentread';
} else {
$tpl = 'sentedit';
}
if (is_array($props)) {
$props['show'] = $show;
}
// 输出引用
$arrSid = explode('-', $sid);
$bookPara = array_slice($arrSid, 0, 2);
if (! isset($GLOBALS['ref_sent'])) {
$GLOBALS['ref_sent'] = [];
}
$GLOBALS['ref_sent'][] = $bookPara;
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'tag' => 'span',
'tpl' => $tpl,
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => $tpl,
];
break;
case 'text':
$output = '';
if (isset($props['origin']) && is_array($props['origin'])) {
foreach ($props['origin'] as $key => $value) {
$output .= $value['html'];
}
}
if (isset($props['translation']) && is_array($props['translation'])) {
foreach ($props['translation'] as $key => $value) {
$output .= $value['html'];
}
}
break;
case 'prompt':
$output = '';
if ($show === 'both' || $show === 'origin') {
if (isset($props['origin']) && is_array($props['origin'])) {
foreach ($props['origin'] as $key => $value) {
$output .= $value['html'];
}
}
}
if ($show === 'both' || $show === 'translation') {
if (isset($props['translation']) && is_array($props['translation'])) {
foreach ($props['translation'] as $key => $value) {
$output .= $value['html'];
}
}
}
break;
case 'html':
$output = '';
$output .= '';
if ($show === 'both' || $show === 'origin') {
if (isset($props['origin']) && is_array($props['origin'])) {
foreach ($props['origin'] as $key => $value) {
$output .= ''.$value['html'].'';
}
}
}
if ($show === 'both' || $show === 'translation') {
if (isset($props['translation']) && is_array($props['translation'])) {
foreach ($props['translation'] as $key => $value) {
$output .= ''.$value['html'].'';
}
}
}
$output .= '';
break;
case 'tex':
$output = '';
if (isset($props['translation']) && is_array($props['translation'])) {
foreach ($props['translation'] as $key => $value) {
$output .= $value['html'];
}
}
break;
case 'simple':
$output = '';
if ($show === 'both' || $show === 'origin') {
if (empty($output)) {
if (
isset($props['origin']) &&
is_array($props['origin']) &&
count($props['origin']) > 0
) {
foreach ($props['origin'] as $key => $value) {
$output .= trim($value['html']);
}
}
}
}
if ($show === 'both' || $show === 'translation') {
if (
isset($props['translation']) &&
is_array($props['translation']) &&
count($props['translation']) > 0
) {
foreach ($props['translation'] as $key => $value) {
$output .= trim($value['html']);
}
}
}
break;
case 'markdown':
$output = '';
if ($show === 'both' || $show === 'origin') {
if (
$this->options['origin'] === true ||
$this->options['origin'] === 'true'
) {
if (isset($props['origin']) && is_array($props['origin'])) {
foreach ($props['origin'] as $key => $value) {
$output .= trim($value['html']);
}
}
}
}
if ($show === 'both' || $show === 'translation') {
if (
$this->options['translation'] === true ||
$this->options['translation'] === 'true'
) {
if (
isset($props['translation']) &&
is_array($props['translation']) &&
count($props['translation']) > 0
) {
foreach ($props['translation'] as $key => $value) {
$output .= trim($value['html']);
}
} else {
if ($show === 'translation') {
// 无译文用原文代替
if (isset($props['origin']) && is_array($props['origin'])) {
foreach ($props['origin'] as $key => $value) {
$output .= trim($value['html']);
}
}
}
}
}
}
break;
default:
$output = '';
break;
}
return $output;
}
private function render_mermaid()
{
$text = json_decode(base64_decode($this->get_param($this->param, 'text', 1)));
$props = ['text' => implode("\n", $text)];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => 'mermaid',
'tag' => 'div',
'tpl' => 'mermaid',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'mermaid',
];
break;
case 'text':
$output = 'mermaid';
break;
case 'tex':
$output = 'mermaid';
break;
case 'simple':
$output = 'mermaid';
break;
default:
$output = 'mermaid';
break;
}
return $output;
}
private function render_qa()
{
$id = $this->get_param($this->param, 'id', 1);
$style = $this->get_param($this->param, 'style', 2);
$props = [
'type' => 'qa',
'id' => $id,
'title' => '',
'style' => $style,
];
$qa = Discussion::where('id', $id)->first();
if ($qa) {
$props['title'] = $qa->title;
$props['resId'] = $qa->res_id;
$props['resType'] = $qa->res_type;
}
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'text' => $props['title'],
'tag' => 'div',
'tpl' => 'qa',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'qa',
];
break;
default:
$output = $props['title'];
break;
}
return $output;
}
private function render_grammar_lookup()
{
$word = $this->get_param($this->param, 'word', 1);
$props = ['word' => $word];
$localTermChannel = ChannelApi::getSysChannel(
'_System_Grammar_Term_'.strtolower($this->lang).'_',
'_System_Grammar_Term_en_'
);
$term = $this->getTermProps($word, null, $localTermChannel);
$props['term'] = $term;
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'text' => $props['word'],
'tag' => 'span',
'tpl' => 'grammar',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'grammar',
];
break;
default:
$output = $props['word'];
break;
}
return $output;
}
private function render_video()
{
$url = $this->get_param($this->param, 'url', 1);
$style = $this->get_param($this->param, 'style', 2, 'modal');
$title = $this->get_param($this->param, 'title', 3);
$props = [
'url' => $url,
'title' => $title,
'style' => $style,
];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'text' => $props['title'],
'tag' => 'span',
'tpl' => 'video',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'video',
];
break;
default:
$output = $props['title'];
break;
}
return $output;
}
// 论文后面的参考资料
private function render_ref()
{
$references = [];
$counter = 0;
if (isset($GLOBALS['ref_sent'])) {
$hasBooks = [];
$book_titles = BookSeries::select(['book', 'paragraph', 'title', 'sn'])
->orderBy('sn', 'DESC')->get();
$bTitles = [];
foreach ($book_titles as $key => $book) {
$bTitles[] = [
'book' => $book->book,
'paragraph' => $book->paragraph,
'title' => $book->title,
];
}
foreach ($GLOBALS['ref_sent'] as $key => $ref) {
$books = array_filter($bTitles, function ($value) use ($ref) {
return $value['book'] === (int) $ref[0];
});
if (count($books) > 0) {
foreach ($books as $key => $book) {
if ($book['paragraph'] < (int) $ref[1]) {
if (! isset($hasBooks[$book['title']])) {
$hasBooks[$book['title']] = 1;
$counter++;
$references[] = [
'sn' => $counter,
'title' => $book['title'],
'copyright' => 'CSCD V4 VRI 2008',
];
}
}
}
}
}
}
$props = [
'pali' => $references,
];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'tag' => 'div',
'tpl' => 'reference',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'reference',
];
break;
case 'markdown':
$output = '';
foreach ($references as $key => $reference) {
$output .= '['.$reference['sn'].'] **'.ucfirst($reference['title']).'** ';
$output .= $reference['copyright']."\n\n";
}
break;
default:
$output = '';
foreach ($references as $key => $reference) {
$output .= '['.$reference['sn'].'] '.ucfirst($reference['title']).' ';
$output .= $reference['copyright']."\n";
}
break;
}
return $output;
}
private function render_dict_pref()
{
$currPage = $this->get_param($this->param, 'page', 1, 1);
$pageSize = $this->get_param($this->param, 'size', 2, 100);
$props = [
'currPage' => $currPage,
'pageSize' => $pageSize,
];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'text' => '',
'tag' => 'div',
'tpl' => 'dict-pref',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'dict-pref',
];
break;
default:
$output = 'dict-pref';
break;
}
return $output;
}
private function render_ai()
{
$model = $this->get_param($this->param, 'model', 1, 1);
$props = [
'model' => $model,
];
switch ($this->format) {
case 'react':
$output = [
'props' => base64_encode(\json_encode($props)),
'html' => '',
'text' => '',
'tag' => 'div',
'tpl' => 'ai',
];
break;
case 'unity':
$output = [
'props' => base64_encode(\json_encode($props)),
'tpl' => 'ai',
];
break;
case 'text':
$output = 'ai';
break;
case 'prompt':
$output = '';
break;
default:
$output = 'ai';
break;
}
return $output;
}
private function get_param(array $param, string $name, int $id, string $default = '')
{
if (isset($param[$name])) {
return trim($param[$name]);
} elseif (isset($param["{$id}"])) {
return trim($param["{$id}"]);
} else {
return $default;
}
}
private function mb_trim($str, string $character_mask = ' ', $charset = 'UTF-8')
{
$start = 0;
$end = mb_strlen($str, $charset) - 1;
$chars = preg_split('//u', $character_mask, -1, PREG_SPLIT_NO_EMPTY);
while ($start <= $end && in_array(mb_substr($str, $start, 1, $charset), $chars)) {
$start++;
}
while ($end >= $start && in_array(mb_substr($str, $end, 1, $charset), $chars)) {
$end--;
}
return mb_substr($str, $start, $end - $start + 1, $charset);
}
}