TemplateRender.php 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506
  1. <?php
  2. namespace App\Http\Api;
  3. use Illuminate\Support\Facades\Cache;
  4. use Illuminate\Support\Facades\Log;
  5. use Illuminate\Support\Str;
  6. use Illuminate\Support\Facades\Http;
  7. use App\Models\DhammaTerm;
  8. use App\Models\PaliText;
  9. use App\Models\Channel;
  10. use App\Models\PageNumber;
  11. use App\Models\Discussion;
  12. use App\Models\BookTitle as BookSeries;
  13. use App\Http\Controllers\CorpusController;
  14. use App\Http\Api\ChannelApi;
  15. use App\Http\Api\MdRender;
  16. use App\Http\Api\PaliTextApi;
  17. use App\Tools\Tools;
  18. use App\Services\ArticleService;
  19. class TemplateRender
  20. {
  21. protected $param = [];
  22. protected $mode = "read";
  23. protected $channel_id = [];
  24. protected $debug = [];
  25. protected $format = 'react';
  26. protected $studioId = null;
  27. protected $lang = 'en';
  28. protected $langFamily = 'en';
  29. protected $glossaryKey = 'glossary';
  30. protected $channelInfo = [];
  31. protected $options = [
  32. 'mode' => 'read',
  33. 'channelType' => 'translation',
  34. 'contentType' => "markdown",
  35. 'format' => 'react',
  36. 'debug' => [],
  37. 'studioId' => null,
  38. 'lang' => 'zh-Hans',
  39. 'footnote' => false,
  40. 'paragraph' => false,
  41. 'origin' => true,
  42. 'translation' => true,
  43. ];
  44. /**
  45. * Create a new command instance.
  46. * string $mode 'read' | 'edit'
  47. * string $format 'react' | 'text' | 'tex' | 'unity'
  48. * @return void
  49. */
  50. public function __construct(array $param, $channelInfo, string $mode, string $format = 'react', ?string $studioId = null, $debug = [], $lang = 'zh-Hans')
  51. {
  52. $this->param = $param;
  53. foreach ($channelInfo as $channel) {
  54. if ($channel && isset($channel->uid)) {
  55. $this->channel_id[] = $channel->uid;
  56. } else {
  57. Log::error('template render init error invalid channel');
  58. }
  59. }
  60. $this->channelInfo = $channelInfo;
  61. $this->mode = $mode;
  62. $this->format = $format;
  63. $this->studioId = $studioId;
  64. $this->debug = $debug;
  65. $this->glossaryKey = 'glossary';
  66. if (count($this->channel_id) > 0) {
  67. $channelId = $this->channel_id[0];
  68. if (Str::isUuid($channelId)) {
  69. $lang = Channel::where('uid', $channelId)->value('lang');
  70. }
  71. }
  72. if (!empty($lang)) {
  73. $this->lang = $lang;
  74. $this->langFamily = explode('-', $lang)[0];
  75. }
  76. }
  77. public function options($options = [])
  78. {
  79. foreach ($options as $key => $value) {
  80. $this->options[$key] = $value;
  81. }
  82. }
  83. public function glossaryKey()
  84. {
  85. return $this->glossaryKey;
  86. }
  87. /**
  88. * TODO 设置默认语言。在渲染某些内容的时候需要语言信息
  89. */
  90. public function setLang($lang)
  91. {
  92. $this->lang = $lang;
  93. $this->langFamily = explode('-', $lang)[0];
  94. }
  95. private function info($message, $debug)
  96. {
  97. if (in_array($debug, $this->debug)) {
  98. Log::info($message);
  99. }
  100. }
  101. private function error($message, $debug)
  102. {
  103. if (in_array($debug, $this->debug)) {
  104. Log::error($message);
  105. }
  106. }
  107. public function render($tpl_name)
  108. {
  109. switch ($tpl_name) {
  110. case 'term':
  111. # 术语
  112. $result = $this->render_term();
  113. break;
  114. case 'note':
  115. $result = $this->render_note();
  116. break;
  117. case 'sent':
  118. $result = $this->render_sent();
  119. break;
  120. case 'quote':
  121. $result = $this->render_quote();
  122. break;
  123. case 'ql':
  124. $result = $this->render_quote_link();
  125. break;
  126. case 'exercise':
  127. $result = $this->render_exercise();
  128. break;
  129. case 'article':
  130. $result = $this->render_article();
  131. break;
  132. case 'nissaya':
  133. $result = $this->render_nissaya();
  134. break;
  135. case 'mermaid':
  136. $result = $this->render_mermaid();
  137. break;
  138. case 'qa':
  139. $result = $this->render_qa();
  140. break;
  141. case 'v':
  142. $result = $this->render_video();
  143. break;
  144. case 'g':
  145. $result = $this->render_grammar_lookup();
  146. break;
  147. case 'ref':
  148. $result = $this->render_ref();
  149. break;
  150. case 'dict-pref':
  151. $result = $this->render_dict_pref();
  152. break;
  153. case 'ai':
  154. $result = $this->render_ai();
  155. break;
  156. case 'para':
  157. $result = $this->render_para();
  158. break;
  159. case 'category':
  160. $result = $this->render_category();
  161. break;
  162. default:
  163. if (mb_substr($tpl_name, 0, 4, "UTF-8") === 'Tpl:') {
  164. $result = $this->render_tpl($tpl_name);
  165. } else {
  166. $result = [
  167. 'props' => base64_encode(\json_encode([])),
  168. 'html' => '',
  169. 'tag' => 'span',
  170. 'tpl' => 'unknown',
  171. ];
  172. }
  173. break;
  174. }
  175. return $result;
  176. }
  177. public function render_tpl($name)
  178. {
  179. $article = app(ArticleService::class)->getRawByTitle($name);
  180. $content = $article->content;
  181. if (count($this->param) > 0) {
  182. $m = new \Mustache_Engine(array(
  183. 'entity_flags' => ENT_QUOTES,
  184. 'escape' => function ($value) {
  185. return $value;
  186. }
  187. ));
  188. $content = $m->render($content, $this->param);
  189. }
  190. $output = [];
  191. switch ($this->format) {
  192. case 'react':
  193. $output = [
  194. 'props' => base64_encode(\json_encode(['content' => $content])),
  195. 'html' => $content,
  196. 'tag' => 'span',
  197. 'tpl' => 'tpl',
  198. ];
  199. break;
  200. default:
  201. $output = $content;
  202. break;
  203. }
  204. return $output;
  205. }
  206. public function render_para()
  207. {
  208. $props = [];
  209. $props['id'] = $this->get_param($this->param, "id", 1);
  210. $props['title'] = $this->get_param($this->param, "title", 2);
  211. $props['style'] = $this->get_param($this->param, "style", 3);
  212. $output = [];
  213. switch ($this->format) {
  214. case 'react':
  215. $output = [
  216. 'props' => base64_encode(\json_encode($props)),
  217. 'html' => $props['title'],
  218. 'tag' => 'span',
  219. 'tpl' => 'para',
  220. ];
  221. break;
  222. default:
  223. $output = $props['title'];
  224. break;
  225. }
  226. return $output;
  227. }
  228. public function render_category()
  229. {
  230. $props = [];
  231. $props['name'] = $this->get_param($this->param, "name", 1);
  232. $output = [];
  233. switch ($this->format) {
  234. case 'react':
  235. $output = [
  236. 'props' => base64_encode(\json_encode($props)),
  237. 'html' => $props['name'],
  238. 'tag' => 'span',
  239. 'tpl' => 'para',
  240. ];
  241. break;
  242. default:
  243. $output = $props['name'];
  244. break;
  245. }
  246. return $output;
  247. }
  248. public function getTermProps($word, $tag = null, $channel = null)
  249. {
  250. if ($channel && !empty($channel)) {
  251. $channelId = $channel;
  252. } else {
  253. if (count($this->channel_id) > 0) {
  254. $channelId = $this->channel_id[0];
  255. } else {
  256. $channelId = null;
  257. }
  258. }
  259. if (count($this->channelInfo) === 0) {
  260. if (!empty($channel)) {
  261. $channelInfo = Channel::where('uid', $channel)->first();
  262. if (!$channelInfo) {
  263. unset($channelInfo);
  264. }
  265. }
  266. if (!isset($channelInfo)) {
  267. Log::warning('channel is null');
  268. $output = [
  269. "word" => $word,
  270. 'innerHtml' => '',
  271. ];
  272. return $output;
  273. }
  274. } else {
  275. $channelInfo = $this->channelInfo[0];
  276. }
  277. if (Str::isUuid($channelId)) {
  278. $lang = Channel::where('uid', $channelId)->value('lang');
  279. if (!empty($lang)) {
  280. $langFamily = explode('-', $lang)[0];
  281. } else {
  282. $langFamily = 'zh';
  283. }
  284. $this->info("term:{$word} 先查属于这个channel 的", 'term');
  285. $this->info('channel id' . $channelId, 'term');
  286. $table = DhammaTerm::where("word", $word)
  287. ->where('channal', $channelId);
  288. if ($tag && !empty($tag)) {
  289. $table = $table->where('tag', $tag);
  290. }
  291. $tplParam = $table->orderBy('updated_at', 'desc')
  292. ->first();
  293. $studioId = $channelInfo->owner_uid;
  294. } else {
  295. $tplParam = false;
  296. $lang = '';
  297. $langFamily = '';
  298. $studioId = $this->studioId;
  299. }
  300. if (!$tplParam) {
  301. if (Str::isUuid($studioId)) {
  302. /**
  303. * 没有,再查这个studio的
  304. * 按照语言过滤
  305. * 完全匹配的优先
  306. * 语族匹配也行
  307. */
  308. $this->info("没有-再查这个studio的", 'term');
  309. $table = DhammaTerm::where("word", $word);
  310. if (!empty($tag)) {
  311. $table = $table->where('tag', $tag);
  312. }
  313. $termsInStudio = $table->where('owner', $channelInfo->owner_uid)
  314. ->orderBy('updated_at', 'desc')
  315. ->get();
  316. if (count($termsInStudio) > 0) {
  317. $list = array();
  318. foreach ($termsInStudio as $key => $term) {
  319. if (empty($term->channal)) {
  320. if ($term->language === $lang) {
  321. $list[$term->guid] = 2;
  322. } else if (strpos($term->language, $langFamily) !== false) {
  323. $list[$term->guid] = 1;
  324. }
  325. }
  326. }
  327. if (count($list) > 0) {
  328. arsort($list);
  329. foreach ($list as $key => $one) {
  330. foreach ($termsInStudio as $term) {
  331. if ($term->guid === $key) {
  332. $tplParam = $term;
  333. break;
  334. }
  335. }
  336. break;
  337. }
  338. }
  339. }
  340. }
  341. }
  342. if (!$tplParam) {
  343. $this->info("没有,再查社区", 'term');
  344. $community_channel = ChannelApi::getSysChannel("_community_term_zh-hans_");
  345. $table = DhammaTerm::where("word", $word);
  346. if (!empty($tag)) {
  347. $table = $table->where('tag', $tag);
  348. }
  349. $tplParam = $table->where('channal', $community_channel)
  350. ->first();
  351. if ($tplParam) {
  352. $isCommunity = true;
  353. } else {
  354. $this->info("查社区没有", 'term');
  355. }
  356. }
  357. $output = [
  358. "word" => $word,
  359. "parentChannelId" => $channelId,
  360. "parentStudioId" => $channelInfo ? $channelInfo->owner_uid : null,
  361. ];
  362. $innerString = $output["word"];
  363. if ($tplParam) {
  364. $output["id"] = $tplParam->guid;
  365. $output["meaning"] = $tplParam->meaning;
  366. $output["channel"] = $tplParam->channal;
  367. if (!empty($tplParam->note)) {
  368. $mdRender = new MdRender(['format' => $this->format]);
  369. $output['note'] = $mdRender->convert($tplParam->note, $this->channel_id);
  370. }
  371. if (isset($isCommunity)) {
  372. $output["isCommunity"] = true;
  373. }
  374. $innerString = "{$output["meaning"]}({$output["word"]})";
  375. if (!empty($tplParam->other_meaning)) {
  376. $output["meaning2"] = $tplParam->other_meaning;
  377. }
  378. }
  379. $output['innerHtml'] = $innerString;
  380. return $output;
  381. }
  382. private function render_term()
  383. {
  384. $word = $this->get_param($this->param, "word", 1);
  385. if (str_contains($word, '@')) {
  386. [$wordHead, $tag] = explode('@', $word);
  387. }
  388. if (str_contains($word, '#')) {
  389. [$wordHead, $display] = explode('#', $word);
  390. }
  391. $props = $this->getTermProps($wordHead ?? $word, $tag ?? '');
  392. if (isset($display)) {
  393. $props['meaning'] = $display;
  394. }
  395. $output = $props['word'];
  396. switch ($this->format) {
  397. case 'react':
  398. $output = [
  399. 'props' => base64_encode(\json_encode($props)),
  400. 'html' => $props['innerHtml'],
  401. 'tag' => 'span',
  402. 'tpl' => 'term',
  403. ];
  404. break;
  405. case 'unity':
  406. $output = [
  407. 'props' => base64_encode(\json_encode($props)),
  408. 'tpl' => 'term',
  409. ];
  410. break;
  411. case 'html':
  412. $no = isset($props['id']) ? '' : 'term_invalid';
  413. $id = isset($props['id']) ? $props['id'] : '';
  414. $output = "<span ";
  415. $output .= "class='term-ref {$no}' ";
  416. $output .= "data-id='{$id}' ";
  417. $output .= "data-term='{$props['word']}' ";
  418. $output .= ">";
  419. $output .= $props['meaning'] ?? $props['word'];
  420. $output .= "</span>";
  421. break;
  422. case 'markdown':
  423. if (isset($props["meaning"])) {
  424. $key = 'term-' . $props["word"];
  425. if (isset($GLOBALS[$key]) && $GLOBALS[$key] === 1) {
  426. $GLOBALS[$key]++;
  427. $output = $props["meaning"];
  428. } else {
  429. $GLOBALS[$key] = 1;
  430. $output = $props["meaning"] . '(' . $props["word"] . ')';
  431. }
  432. } else {
  433. $output = $props["word"];
  434. }
  435. //如果有内容且第一次出现,显示为脚注
  436. if (!empty($props["note"]) && $GLOBALS[$key] === 1) {
  437. if (isset($GLOBALS['note_sn'])) {
  438. $GLOBALS['note_sn']++;
  439. } else {
  440. $GLOBALS['note_sn'] = 1;
  441. $GLOBALS['note'] = array();
  442. }
  443. $content = $props["note"];
  444. $output .= '[^' . $GLOBALS['note_sn'] . ']';
  445. $GLOBALS['note'][] = [
  446. 'sn' => $GLOBALS['note_sn'],
  447. 'trigger' => '',
  448. 'content' => $content,
  449. ];
  450. }
  451. break;
  452. default:
  453. $output = $props['meaning'] ?? $props['word'];
  454. break;
  455. }
  456. return $output;
  457. }
  458. private function render_note()
  459. {
  460. $note = $this->get_param($this->param, "text", 1);
  461. $trigger = $this->get_param($this->param, "trigger", 2, '');
  462. $props = ["note" => $note];
  463. $innerString = "";
  464. if (!empty($trigger)) {
  465. $props["trigger"] = $trigger;
  466. $innerString = $props["trigger"];
  467. }
  468. if ($this->format === 'unity') {
  469. $props["note"] = MdRender::render(
  470. $props["note"],
  471. $this->channel_id,
  472. null,
  473. 'read',
  474. 'translation',
  475. 'markdown',
  476. 'unity'
  477. );
  478. }
  479. $output = $note;
  480. switch ($this->format) {
  481. case 'react':
  482. $output = [
  483. 'props' => base64_encode(\json_encode($props)),
  484. 'html' => $innerString,
  485. 'tag' => 'span',
  486. 'tpl' => 'note',
  487. ];
  488. break;
  489. case 'unity':
  490. $output = [
  491. 'props' => base64_encode(\json_encode($props)),
  492. 'tpl' => 'note',
  493. ];
  494. break;
  495. case 'html':
  496. if (isset($GLOBALS['note_sn'])) {
  497. $GLOBALS['note_sn']++;
  498. } else {
  499. $GLOBALS['note_sn'] = 1;
  500. $GLOBALS['note'] = array();
  501. }
  502. $noteContent = MdRender::render(
  503. $props["note"],
  504. $this->channel_id,
  505. null,
  506. 'read',
  507. 'translation',
  508. 'markdown',
  509. 'html'
  510. );
  511. $GLOBALS['note'][] = [
  512. 'sn' => $GLOBALS['note_sn'],
  513. 'trigger' => $trigger,
  514. 'content' => $noteContent,
  515. ];
  516. $link = "<a href='#footnote-" . $GLOBALS['note_sn'] . "' name='note-" . $GLOBALS['note_sn'] . "'>";
  517. if (empty($trigger)) {
  518. $output = $link . "<sup>[" . $GLOBALS['note_sn'] . "]</sup></a>";
  519. } else {
  520. $output = $link . $trigger . "</a>";
  521. }
  522. $output = "<label for=\"sn-{$GLOBALS['note_sn']}\"
  523. class=\"margin-toggle sidenote-number\" >{$trigger}</label>
  524. <input type=\"checkbox\" id=\"sn-{$GLOBALS['note_sn']}\"
  525. class=\"margin-toggle\"/>
  526. <span class=\"sidenote\">{$noteContent}</span>";
  527. break;
  528. case 'text':
  529. $output = $trigger;
  530. break;
  531. case 'tex':
  532. $output = $trigger;
  533. break;
  534. case 'simple':
  535. $output = '';
  536. break;
  537. case 'markdown':
  538. if (isset($GLOBALS['note_sn'])) {
  539. $GLOBALS['note_sn']++;
  540. } else {
  541. $GLOBALS['note_sn'] = 1;
  542. $GLOBALS['note'] = array();
  543. }
  544. $content = MdRender::render(
  545. $props["note"],
  546. $this->channel_id,
  547. null,
  548. 'read',
  549. 'translation',
  550. 'markdown',
  551. 'markdown'
  552. );
  553. $output = '[^' . $GLOBALS['note_sn'] . ']';
  554. $GLOBALS['note'][] = [
  555. 'sn' => $GLOBALS['note_sn'],
  556. 'trigger' => $trigger,
  557. 'content' => $content,
  558. ];
  559. //$output = '<footnote id="'.$GLOBALS['note_sn'].'">'.$content.'</footnote>';
  560. break;
  561. default:
  562. $output = '';
  563. break;
  564. }
  565. return $output;
  566. }
  567. private function render_nissaya()
  568. {
  569. $pali = $this->get_param($this->param, "pali", 1);
  570. $meaning = $this->get_param($this->param, "meaning", 2);
  571. $innerString = "";
  572. $props = [
  573. "pali" => $pali,
  574. "meaning" => explode('=', $meaning),
  575. "lang" => $this->lang,
  576. ];
  577. switch ($this->format) {
  578. case 'react':
  579. $output = [
  580. 'props' => base64_encode(\json_encode($props)),
  581. 'html' => $innerString,
  582. 'tag' => 'span',
  583. 'tpl' => 'nissaya',
  584. ];
  585. break;
  586. case 'unity':
  587. $output = [
  588. 'props' => base64_encode(\json_encode($props)),
  589. 'tpl' => 'nissaya',
  590. ];
  591. break;
  592. case 'prompt':
  593. $output = Tools::MyToRm($pali) . ':' . end($props["meaning"]);
  594. break;
  595. default:
  596. $output = $pali . '၊' . $meaning;
  597. break;
  598. }
  599. return $output;
  600. }
  601. private function render_exercise()
  602. {
  603. $id = $this->get_param($this->param, "id", 1);
  604. $title = $this->get_param($this->param, "title", 1);
  605. $props = [
  606. "id" => $id,
  607. "title" => $title,
  608. "channel" => $this->channel_id[0],
  609. ];
  610. switch ($this->format) {
  611. case 'react':
  612. $output = [
  613. 'props' => base64_encode(\json_encode($props)),
  614. 'html' => "",
  615. 'tag' => 'span',
  616. 'tpl' => 'exercise',
  617. ];
  618. break;
  619. case 'unity':
  620. $output = [
  621. 'props' => base64_encode(\json_encode($props)),
  622. 'tpl' => 'exercise',
  623. ];
  624. break;
  625. case 'text':
  626. $output = $title;
  627. break;
  628. case 'tex':
  629. $output = $title;
  630. break;
  631. case 'simple':
  632. $output = $title;
  633. break;
  634. default:
  635. $output = '';
  636. break;
  637. }
  638. return $output;
  639. }
  640. private function render_article()
  641. {
  642. $type = $this->get_param($this->param, "type", 1);
  643. $id = $this->get_param($this->param, "id", 2);
  644. $title = $this->get_param($this->param, "title", 3);
  645. $channel = $this->get_param($this->param, "channel", 4);
  646. $style = $this->get_param($this->param, "style", 5);
  647. $book = $this->get_param($this->param, "book", 6);
  648. $paragraphs = $this->get_param($this->param, "paragraphs", 7);
  649. $anthology = $this->get_param($this->param, "anthology", 8);
  650. if ($type === 'chapter' && empty($id)) {
  651. $book = (int)$book;
  652. $paragraphs = (int)$paragraphs;
  653. $id = "{$book}-{$paragraphs}";
  654. }
  655. $props = [
  656. "type" => $type,
  657. "id" => $id,
  658. 'style' => $style,
  659. ];
  660. if (!empty($channel)) {
  661. $props['channel'] = $channel;
  662. }
  663. if (!empty($title)) {
  664. $props['title'] = $title;
  665. }
  666. if (!empty($book)) {
  667. $props['book'] = $book;
  668. }
  669. if (!empty($paragraphs)) {
  670. $props['paragraphs'] = $paragraphs;
  671. }
  672. if (!empty($anthology)) {
  673. $props['anthology'] = $anthology;
  674. }
  675. if (is_array($this->channel_id)) {
  676. $props['parentChannels'] = $this->channel_id;
  677. }
  678. switch ($this->format) {
  679. case 'react':
  680. $output = [
  681. 'props' => base64_encode(\json_encode($props)),
  682. 'html' => "",
  683. 'text' => $title,
  684. 'tag' => 'span',
  685. 'tpl' => 'article',
  686. ];
  687. break;
  688. case 'unity':
  689. $output = [
  690. 'props' => base64_encode(\json_encode($props)),
  691. 'tpl' => 'article',
  692. ];
  693. break;
  694. case 'text':
  695. $output = $title;
  696. break;
  697. case 'tex':
  698. $output = $title;
  699. break;
  700. case 'simple':
  701. $output = $title;
  702. break;
  703. default:
  704. $output = '';
  705. break;
  706. }
  707. return $output;
  708. }
  709. private function render_quote()
  710. {
  711. $paraId = $this->get_param($this->param, "para", 1);
  712. $channelId = $this->channel_id[0];
  713. $props = Cache::remember(
  714. "/quote/{$channelId}/{$paraId}",
  715. config('mint.cache.expire'),
  716. function () use ($paraId, $channelId) {
  717. $para = \explode('-', $paraId);
  718. $output = [
  719. "paraId" => $paraId,
  720. "channel" => $channelId,
  721. "innerString" => $paraId,
  722. ];
  723. if (count($para) < 2) {
  724. return $output;
  725. }
  726. $PaliText = PaliText::where("book", $para[0])
  727. ->where("paragraph", $para[1])
  728. ->select(['toc', 'path'])
  729. ->first();
  730. if ($PaliText) {
  731. $output["pali"] = $PaliText->toc;
  732. $output["paliPath"] = \json_decode($PaliText->path);
  733. $output["innerString"] = $PaliText->toc;
  734. }
  735. return $output;
  736. }
  737. );
  738. switch ($this->format) {
  739. case 'react':
  740. $output = [
  741. 'props' => base64_encode(\json_encode($props)),
  742. 'html' => $props["innerString"],
  743. 'tag' => 'span',
  744. 'tpl' => 'quote',
  745. ];
  746. break;
  747. case 'unity':
  748. $output = [
  749. 'props' => base64_encode(\json_encode($props)),
  750. 'tpl' => 'quote',
  751. ];
  752. break;
  753. case 'text':
  754. $output = $props["innerString"];
  755. break;
  756. case 'tex':
  757. $output = $props["innerString"];
  758. break;
  759. case 'simple':
  760. $output = $props["innerString"];
  761. break;
  762. default:
  763. $output = $props["innerString"];
  764. break;
  765. }
  766. return $output;
  767. }
  768. private function render_quote_link()
  769. {
  770. $type = $this->get_param($this->param, "type", 1);
  771. $title = $this->get_param($this->param, "title", 6, '');
  772. $bookName = $this->get_param($this->param, "bookname", 2, '');
  773. $volume = $this->get_param($this->param, "volume", 3);
  774. $page = $this->get_param($this->param, "page", 4, '');
  775. $style = $this->get_param($this->param, "style", 5, 'modal');
  776. $book = $this->get_param($this->param, "book", 7, false);
  777. $para = $this->get_param($this->param, "para", 8, false);
  778. $props = [
  779. 'type' => $type,
  780. 'style' => $style,
  781. 'found' => true,
  782. ];
  783. if (!empty($bookName) && $volume !== '' && !empty($page)) {
  784. $props['bookName'] = $bookName;
  785. $props['volume'] = (int)$volume;
  786. $props['page'] = $page;
  787. $props['found'] = true;
  788. } else if ($book && $para) {
  789. /**
  790. * 没有指定书名,根据book para 查询
  791. */
  792. if ($type === 'c') {
  793. //按照章节名称显示
  794. $path = PaliTextApi::getChapterPath($book, $para);
  795. if ($path) {
  796. $path = json_decode($path, true);
  797. }
  798. if ($path && is_array($path) && count($path) > 2) {
  799. $props['bookName'] = strtolower($path[0]['title']);
  800. $props['chapter'] = strtolower(end($path)['title']);
  801. $props['found'] = true;
  802. } else {
  803. $props['found'] = false;
  804. }
  805. } else {
  806. $pageInfo = $this->pageInfoByPara($type, $book, $para);
  807. if ($pageInfo['found']) {
  808. $props['bookName'] = $pageInfo['bookName'];
  809. $props['volume'] = $pageInfo['volume'];
  810. $props['page'] = $pageInfo['page'];
  811. $props['found'] = true;
  812. } else {
  813. $props['found'] = false;
  814. }
  815. }
  816. } else if ($title) {
  817. //没有书号用title查询
  818. //$tmpTitle = explode('။',$title);
  819. for ($i = mb_strlen($title, 'UTF-8'); $i > 0; $i--) {
  820. $mTitle = mb_substr($title, 0, $i);
  821. $has = array_search($mTitle, array_column(BookTitle::my(), 'title2'));
  822. Log::debug('run', ['title' => $mTitle, 'has' => $has]);
  823. if ($has !== false) {
  824. $tmpBookTitle = $mTitle;
  825. $tmpBookPage = mb_substr($title, $i);
  826. $tmpBookPage = $this->mb_trim($tmpBookPage, '၊။');
  827. break;
  828. }
  829. }
  830. if (isset($tmpBookTitle)) {
  831. Log::debug('book title found', ['title' => $tmpBookTitle, 'page' => $tmpBookPage]);
  832. //$tmpBookTitle = $tmpTitle[0];
  833. //$tmpBookPage = $tmpTitle[1];
  834. $tmpBookPage = (int)str_replace(
  835. ['၁', '၂', '၃', '၄', '၅', '၆', '၇', '၈', '၉', '၀'],
  836. ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
  837. $tmpBookPage
  838. );
  839. $found_key = array_search($tmpBookTitle, array_column(BookTitle::my(), 'title2'));
  840. if ($found_key !== false) {
  841. $props['bookName'] = BookTitle::my()[$found_key]['bookname'];
  842. $props['volume'] = BookTitle::my()[$found_key]['volume'];
  843. $props['page'] = $tmpBookPage;
  844. if (!empty($props['bookName'])) {
  845. $found_title = array_search($props['bookName'], array_column(BookTitle::my(), 'bookname'));
  846. if ($found_title === false) {
  847. $props['found'] = false;
  848. }
  849. }
  850. } else {
  851. //没找到,返回术语和页码
  852. $props['found'] = false;
  853. $props['bookName'] = $tmpBookTitle;
  854. $props['page'] = $tmpBookPage;
  855. $props['volume'] = 0;
  856. }
  857. }
  858. } else {
  859. Log::debug('book title not found');
  860. $props['found'] = false;
  861. }
  862. if ($book && $para) {
  863. $props['book'] = $book;
  864. $props['para'] = $para;
  865. }
  866. if ($title) {
  867. $props['title'] = $title;
  868. }
  869. $text = '';
  870. if (isset($props['bookName'])) {
  871. $searchField = '';
  872. switch ($type) {
  873. case 'm':
  874. $searchField = 'm_title';
  875. break;
  876. case 'p':
  877. $searchField = 'p_title';
  878. break;
  879. }
  880. $found_title = array_search($props['bookName'], array_column(BookTitle::get(), $searchField));
  881. if ($found_title === false) {
  882. $props['found'] = false;
  883. }
  884. $term = $this->getTermProps($props['bookName'], ':quote:');
  885. $props['term'] = $term;
  886. if (isset($term['id'])) {
  887. $props['bookNameLocal'] = $term['meaning'];
  888. $text .= $term['meaning'];
  889. } else {
  890. $text .= $bookName;
  891. }
  892. }
  893. if (isset($props['volume']) && isset($props['page'])) {
  894. $text .= " {$volume}.{$page}";
  895. }
  896. switch ($this->format) {
  897. case 'react':
  898. $output = [
  899. 'props' => base64_encode(\json_encode($props)),
  900. 'html' => '',
  901. 'tag' => 'span',
  902. 'tpl' => 'quote-link',
  903. ];
  904. break;
  905. case 'unity':
  906. $output = [
  907. 'props' => base64_encode(\json_encode($props)),
  908. 'tpl' => 'quote-link',
  909. ];
  910. break;
  911. default:
  912. $output = $text;
  913. break;
  914. }
  915. return $output;
  916. }
  917. private function pageInfoByPara($type, $book, $para)
  918. {
  919. $output = array();
  920. $pageInfo = PageNumber::where('type', strtoupper($type))
  921. ->where('book', $book)
  922. ->where('paragraph', '<=', $para)
  923. ->orderBy('paragraph', 'desc')
  924. ->first();
  925. if ($pageInfo) {
  926. foreach (BookTitle::get() as $value) {
  927. if ($value['id'] === $pageInfo->pcd_book_id) {
  928. switch (strtoupper($type)) {
  929. case 'M':
  930. $key = 'm_title';
  931. break;
  932. case 'P':
  933. $key = 'p_title';
  934. break;
  935. case 'V':
  936. $key = 'v_title';
  937. break;
  938. default:
  939. $key = 'term';
  940. break;
  941. }
  942. $output['bookName'] = $value[$key];
  943. break;
  944. }
  945. }
  946. $output['volume'] = $pageInfo->volume;
  947. $output['page'] = $pageInfo->page;
  948. $output['found'] = true;
  949. } else {
  950. $output['found'] = false;
  951. }
  952. return $output;
  953. }
  954. private function render_sent()
  955. {
  956. $sid = $this->get_param($this->param, "id", 1);
  957. $channel = $this->get_param($this->param, "channel", 2);
  958. $show = $this->get_param($this->param, "text", 2, 'both');
  959. if (!empty($channel)) {
  960. $channels = explode(',', $channel);
  961. } else {
  962. $channels = $this->channel_id;
  963. }
  964. $sentInfo = explode('@', trim($sid));
  965. $sentId = $sentInfo[0];
  966. if (isset($sentInfo[1])) {
  967. $channels = [$sentInfo[1]];
  968. }
  969. $Sent = new CorpusController();
  970. $props = $Sent->getSentTpl(
  971. $sentId,
  972. $channels,
  973. $this->mode,
  974. true,
  975. $this->format
  976. );
  977. if (!$props) {
  978. $props['error'] = "句子模版渲染错误。句子参数个数不符。应该是四个。";
  979. Log::error('句子模版渲染错误。句子参数个数不符。应该是四个。');
  980. }
  981. if ($this->mode === 'read') {
  982. $tpl = "sentread";
  983. } else {
  984. $tpl = "sentedit";
  985. }
  986. if (is_array($props)) {
  987. $props['show'] = $show;
  988. }
  989. //输出引用
  990. $arrSid = explode('-', $sid);
  991. $bookPara = array_slice($arrSid, 0, 2);
  992. if (!isset($GLOBALS['ref_sent'])) {
  993. $GLOBALS['ref_sent'] = array();
  994. }
  995. $GLOBALS['ref_sent'][] = $bookPara;
  996. switch ($this->format) {
  997. case 'react':
  998. $output = [
  999. 'props' => base64_encode(\json_encode($props)),
  1000. 'html' => "",
  1001. 'tag' => 'span',
  1002. 'tpl' => $tpl,
  1003. ];
  1004. break;
  1005. case 'unity':
  1006. $output = [
  1007. 'props' => base64_encode(\json_encode($props)),
  1008. 'tpl' => $tpl,
  1009. ];
  1010. break;
  1011. case 'text':
  1012. $output = '';
  1013. if (isset($props['origin']) && is_array($props['origin'])) {
  1014. foreach ($props['origin'] as $key => $value) {
  1015. $output .= $value['html'];
  1016. }
  1017. }
  1018. if (isset($props['translation']) && is_array($props['translation'])) {
  1019. foreach ($props['translation'] as $key => $value) {
  1020. $output .= $value['html'];
  1021. }
  1022. }
  1023. break;
  1024. case 'prompt':
  1025. $output = '';
  1026. if ($show === 'both' || $show === 'origin') {
  1027. if (isset($props['origin']) && is_array($props['origin'])) {
  1028. foreach ($props['origin'] as $key => $value) {
  1029. $output .= $value['html'];
  1030. }
  1031. }
  1032. }
  1033. if ($show === 'both' || $show === 'translation') {
  1034. if (isset($props['translation']) && is_array($props['translation'])) {
  1035. foreach ($props['translation'] as $key => $value) {
  1036. $output .= $value['html'];
  1037. }
  1038. }
  1039. }
  1040. break;
  1041. case 'html':
  1042. $output = '';
  1043. $output .= '<span class="sentence">';
  1044. if ($show === 'both' || $show === 'origin') {
  1045. if (isset($props['origin']) && is_array($props['origin'])) {
  1046. foreach ($props['origin'] as $key => $value) {
  1047. $output .= '<span class="origin">' . $value['html'] . '</span>';
  1048. }
  1049. }
  1050. }
  1051. if ($show === 'both' || $show === 'translation') {
  1052. if (isset($props['translation']) && is_array($props['translation'])) {
  1053. foreach ($props['translation'] as $key => $value) {
  1054. $output .= '<span class="translation">' . $value['html'] . '</span>';
  1055. }
  1056. }
  1057. }
  1058. $output .= '</span>';
  1059. break;
  1060. case 'tex':
  1061. $output = '';
  1062. if (isset($props['translation']) && is_array($props['translation'])) {
  1063. foreach ($props['translation'] as $key => $value) {
  1064. $output .= $value['html'];
  1065. }
  1066. }
  1067. break;
  1068. case 'simple':
  1069. $output = '';
  1070. if ($show === 'both' || $show === 'origin') {
  1071. if (empty($output)) {
  1072. if (
  1073. isset($props['origin']) &&
  1074. is_array($props['origin']) &&
  1075. count($props['origin']) > 0
  1076. ) {
  1077. foreach ($props['origin'] as $key => $value) {
  1078. $output .= trim($value['html']);
  1079. }
  1080. }
  1081. }
  1082. }
  1083. if ($show === 'both' || $show === 'translation') {
  1084. if (
  1085. isset($props['translation']) &&
  1086. is_array($props['translation']) &&
  1087. count($props['translation']) > 0
  1088. ) {
  1089. foreach ($props['translation'] as $key => $value) {
  1090. $output .= trim($value['html']);
  1091. }
  1092. }
  1093. }
  1094. break;
  1095. case 'markdown':
  1096. $output = '';
  1097. if ($show === 'both' || $show === 'origin') {
  1098. if (
  1099. $this->options['origin'] === true ||
  1100. $this->options['origin'] === 'true'
  1101. ) {
  1102. if (isset($props['origin']) && is_array($props['origin'])) {
  1103. foreach ($props['origin'] as $key => $value) {
  1104. $output .= trim($value['html']);
  1105. }
  1106. }
  1107. }
  1108. }
  1109. if ($show === 'both' || $show === 'translation') {
  1110. if (
  1111. $this->options['translation'] === true ||
  1112. $this->options['translation'] === 'true'
  1113. ) {
  1114. if (
  1115. isset($props['translation']) &&
  1116. is_array($props['translation']) &&
  1117. count($props['translation']) > 0
  1118. ) {
  1119. foreach ($props['translation'] as $key => $value) {
  1120. $output .= trim($value['html']);
  1121. }
  1122. } else {
  1123. if ($show === 'translation') {
  1124. //无译文用原文代替
  1125. if (isset($props['origin']) && is_array($props['origin'])) {
  1126. foreach ($props['origin'] as $key => $value) {
  1127. $output .= trim($value['html']);
  1128. }
  1129. }
  1130. }
  1131. }
  1132. }
  1133. }
  1134. break;
  1135. default:
  1136. $output = '';
  1137. break;
  1138. }
  1139. return $output;
  1140. }
  1141. private function render_mermaid()
  1142. {
  1143. $text = json_decode(base64_decode($this->get_param($this->param, "text", 1)));
  1144. $props = ["text" => implode("\n", $text)];
  1145. switch ($this->format) {
  1146. case 'react':
  1147. $output = [
  1148. 'props' => base64_encode(\json_encode($props)),
  1149. 'html' => "mermaid",
  1150. 'tag' => 'div',
  1151. 'tpl' => 'mermaid',
  1152. ];
  1153. break;
  1154. case 'unity':
  1155. $output = [
  1156. 'props' => base64_encode(\json_encode($props)),
  1157. 'tpl' => 'mermaid',
  1158. ];
  1159. break;
  1160. case 'text':
  1161. $output = 'mermaid';
  1162. break;
  1163. case 'tex':
  1164. $output = 'mermaid';
  1165. break;
  1166. case 'simple':
  1167. $output = 'mermaid';
  1168. break;
  1169. default:
  1170. $output = 'mermaid';
  1171. break;
  1172. }
  1173. return $output;
  1174. }
  1175. private function render_qa()
  1176. {
  1177. $id = $this->get_param($this->param, "id", 1);
  1178. $style = $this->get_param($this->param, "style", 2);
  1179. $props = [
  1180. "type" => 'qa',
  1181. "id" => $id,
  1182. 'title' => '',
  1183. 'style' => $style,
  1184. ];
  1185. $qa = Discussion::where('id', $id)->first();
  1186. if ($qa) {
  1187. $props['title'] = $qa->title;
  1188. $props['resId'] = $qa->res_id;
  1189. $props['resType'] = $qa->res_type;
  1190. }
  1191. switch ($this->format) {
  1192. case 'react':
  1193. $output = [
  1194. 'props' => base64_encode(\json_encode($props)),
  1195. 'html' => "",
  1196. 'text' => $props['title'],
  1197. 'tag' => 'div',
  1198. 'tpl' => 'qa',
  1199. ];
  1200. break;
  1201. case 'unity':
  1202. $output = [
  1203. 'props' => base64_encode(\json_encode($props)),
  1204. 'tpl' => 'qa',
  1205. ];
  1206. break;
  1207. default:
  1208. $output = $props['title'];
  1209. break;
  1210. }
  1211. return $output;
  1212. }
  1213. private function render_grammar_lookup()
  1214. {
  1215. $word = $this->get_param($this->param, "word", 1);
  1216. $props = ['word' => $word];
  1217. $localTermChannel = ChannelApi::getSysChannel(
  1218. "_System_Grammar_Term_" . strtolower($this->lang) . "_",
  1219. "_System_Grammar_Term_en_"
  1220. );
  1221. $term = $this->getTermProps($word, null, $localTermChannel);
  1222. $props['term'] = $term;
  1223. switch ($this->format) {
  1224. case 'react':
  1225. $output = [
  1226. 'props' => base64_encode(\json_encode($props)),
  1227. 'html' => "",
  1228. 'text' => $props['word'],
  1229. 'tag' => 'span',
  1230. 'tpl' => 'grammar',
  1231. ];
  1232. break;
  1233. case 'unity':
  1234. $output = [
  1235. 'props' => base64_encode(\json_encode($props)),
  1236. 'tpl' => 'grammar',
  1237. ];
  1238. break;
  1239. default:
  1240. $output = $props['word'];
  1241. break;
  1242. }
  1243. return $output;
  1244. }
  1245. private function render_video()
  1246. {
  1247. $url = $this->get_param($this->param, "url", 1);
  1248. $style = $this->get_param($this->param, "style", 2, 'modal');
  1249. $title = $this->get_param($this->param, "title", 3);
  1250. $props = [
  1251. "url" => $url,
  1252. 'title' => $title,
  1253. 'style' => $style,
  1254. ];
  1255. switch ($this->format) {
  1256. case 'react':
  1257. $output = [
  1258. 'props' => base64_encode(\json_encode($props)),
  1259. 'html' => "",
  1260. 'text' => $props['title'],
  1261. 'tag' => 'span',
  1262. 'tpl' => 'video',
  1263. ];
  1264. break;
  1265. case 'unity':
  1266. $output = [
  1267. 'props' => base64_encode(\json_encode($props)),
  1268. 'tpl' => 'video',
  1269. ];
  1270. break;
  1271. default:
  1272. $output = $props['title'];
  1273. break;
  1274. }
  1275. return $output;
  1276. }
  1277. //论文后面的参考资料
  1278. private function render_ref()
  1279. {
  1280. $references = array();
  1281. $counter = 0;
  1282. if (isset($GLOBALS['ref_sent'])) {
  1283. $hasBooks = array();
  1284. $book_titles = BookSeries::select(['book', 'paragraph', 'title', 'sn'])
  1285. ->orderBy('sn', 'DESC')->get();
  1286. $bTitles = array();
  1287. foreach ($book_titles as $key => $book) {
  1288. $bTitles[] = [
  1289. 'book' => $book->book,
  1290. 'paragraph' => $book->paragraph,
  1291. 'title' => $book->title
  1292. ];
  1293. }
  1294. foreach ($GLOBALS['ref_sent'] as $key => $ref) {
  1295. $books = array_filter($bTitles, function ($value) use ($ref) {
  1296. return $value['book'] === (int)$ref[0];
  1297. });
  1298. if (count($books) > 0) {
  1299. foreach ($books as $key => $book) {
  1300. if ($book['paragraph'] < (int)$ref[1]) {
  1301. if (!isset($hasBooks[$book['title']])) {
  1302. $hasBooks[$book['title']] = 1;
  1303. $counter++;
  1304. $references[] = [
  1305. 'sn' => $counter,
  1306. 'title' => $book['title'],
  1307. 'copyright' => 'CSCD V4 VRI 2008'
  1308. ];
  1309. }
  1310. }
  1311. }
  1312. }
  1313. }
  1314. }
  1315. $props = [
  1316. "pali" => $references,
  1317. ];
  1318. switch ($this->format) {
  1319. case 'react':
  1320. $output = [
  1321. 'props' => base64_encode(\json_encode($props)),
  1322. 'html' => '',
  1323. 'tag' => 'div',
  1324. 'tpl' => 'reference',
  1325. ];
  1326. break;
  1327. case 'unity':
  1328. $output = [
  1329. 'props' => base64_encode(\json_encode($props)),
  1330. 'tpl' => 'reference',
  1331. ];
  1332. break;
  1333. case 'markdown':
  1334. $output = '';
  1335. foreach ($references as $key => $reference) {
  1336. $output .= '[' . $reference['sn'] . '] **' . ucfirst($reference['title']) . '** ';
  1337. $output .= $reference['copyright'] . "\n\n";
  1338. }
  1339. break;
  1340. default:
  1341. $output = '';
  1342. foreach ($references as $key => $reference) {
  1343. $output .= '[' . $reference['sn'] . '] ' . ucfirst($reference['title']) . ' ';
  1344. $output .= $reference['copyright'] . "\n";
  1345. }
  1346. break;
  1347. }
  1348. return $output;
  1349. }
  1350. private function render_dict_pref()
  1351. {
  1352. $currPage = $this->get_param($this->param, "page", 1, 1);
  1353. $pageSize = $this->get_param($this->param, "size", 2, 100);
  1354. $props = [
  1355. "currPage" => $currPage,
  1356. 'pageSize' => $pageSize,
  1357. ];
  1358. switch ($this->format) {
  1359. case 'react':
  1360. $output = [
  1361. 'props' => base64_encode(\json_encode($props)),
  1362. 'html' => "",
  1363. 'text' => '',
  1364. 'tag' => 'div',
  1365. 'tpl' => 'dict-pref',
  1366. ];
  1367. break;
  1368. case 'unity':
  1369. $output = [
  1370. 'props' => base64_encode(\json_encode($props)),
  1371. 'tpl' => 'dict-pref',
  1372. ];
  1373. break;
  1374. default:
  1375. $output = 'dict-pref';
  1376. break;
  1377. }
  1378. return $output;
  1379. }
  1380. private function render_ai()
  1381. {
  1382. $model = $this->get_param($this->param, "model", 1, 1);
  1383. $props = [
  1384. "model" => $model,
  1385. ];
  1386. switch ($this->format) {
  1387. case 'react':
  1388. $output = [
  1389. 'props' => base64_encode(\json_encode($props)),
  1390. 'html' => "",
  1391. 'text' => '',
  1392. 'tag' => 'div',
  1393. 'tpl' => 'ai',
  1394. ];
  1395. break;
  1396. case 'unity':
  1397. $output = [
  1398. 'props' => base64_encode(\json_encode($props)),
  1399. 'tpl' => 'ai',
  1400. ];
  1401. break;
  1402. case 'text':
  1403. $output = 'ai';
  1404. break;
  1405. case 'prompt':
  1406. $output = '';
  1407. break;
  1408. default:
  1409. $output = 'ai';
  1410. break;
  1411. }
  1412. return $output;
  1413. }
  1414. private function get_param(array $param, string $name, int $id, string $default = '')
  1415. {
  1416. if (isset($param[$name])) {
  1417. return trim($param[$name]);
  1418. } else if (isset($param["{$id}"])) {
  1419. return trim($param["{$id}"]);
  1420. } else {
  1421. return $default;
  1422. }
  1423. }
  1424. private function mb_trim($str, string $character_mask = ' ', $charset = "UTF-8")
  1425. {
  1426. $start = 0;
  1427. $end = mb_strlen($str, $charset) - 1;
  1428. $chars = preg_split('//u', $character_mask, -1, PREG_SPLIT_NO_EMPTY);
  1429. while ($start <= $end && in_array(mb_substr($str, $start, 1, $charset), $chars)) {
  1430. $start++;
  1431. }
  1432. while ($end >= $start && in_array(mb_substr($str, $end, 1, $charset), $chars)) {
  1433. $end--;
  1434. }
  1435. return mb_substr($str, $start, $end - $start + 1, $charset);
  1436. }
  1437. }