support duplicatable d3forum module.
@@ -29,4 +29,4 @@ dl-limit-items.csv
|
||||
/public/database/items.json
|
||||
/public/database/file
|
||||
/src/database/assets/*.json
|
||||
/src/forum/assets/*.json
|
||||
/src/d3forum/assets/*.json
|
||||
|
||||
@@ -70,7 +70,7 @@ class MyDumpTool
|
||||
$v = $textutil->html_numeric_entities($v);
|
||||
$v = mb_decode_numericentity($v, array(0x0, 0x10000, 0, 0xfffff), 'UTF-8');
|
||||
$data[$k] = \Normalizer::normalize(trim($v), \Normalizer::FORM_C);
|
||||
} else if ($v === null) {
|
||||
} elseif (null === $v) {
|
||||
$data[$k] = '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,24 @@ if (!isset($XOOPS_MODULE_D3FORUM) || empty($XOOPS_MODULE_D3FORUM)) {
|
||||
exit('Not configured for d3forum module'.PHP_EOL);
|
||||
}
|
||||
|
||||
$contents = [];
|
||||
foreach ($XOOPS_MODULE_D3FORUM as $d3forum) {
|
||||
dumpD3Forum($d3forum);
|
||||
dumpD3Forum($d3forum, $contents);
|
||||
}
|
||||
MyDumpTool::makeDirectory('src/d3forum');
|
||||
MyDumpTool::makeDirectory('src/d3forum/assets');
|
||||
MyDumpTool::saveJson('src/d3forum/assets/d3forum.json', $contents);
|
||||
|
||||
function dumpD3Forum($d3forum)
|
||||
function dumpD3Forum($d3forum, &$contents)
|
||||
{
|
||||
global $xoopsDB;
|
||||
$prefix = $xoopsDB->prefix();
|
||||
|
||||
$moduleHandler = xoops_gethandler('module');
|
||||
$module = $moduleHandler->getByDirname($d3forum);
|
||||
$moduleConfigHandler = xoops_gethandler('config');
|
||||
$moduleConfig = $moduleConfigHandler->getConfigsByDirname($d3forum);
|
||||
|
||||
$table = $d3forum.'_categories';
|
||||
if (!MyDumpTool::tableExists($table)) {
|
||||
exit('d3forum('.$d3forum.') module not found'.PHP_EOL);
|
||||
@@ -133,14 +143,20 @@ SQL;
|
||||
//var_dump($posts);
|
||||
var_dump(count($posts));
|
||||
|
||||
$moduleinfo = [
|
||||
'name' => $module->get('name'),
|
||||
'dirname' => $d3forum,
|
||||
'message' => $moduleConfig['top_message'],
|
||||
];
|
||||
MyDumpTool::decode($moduleinfo);
|
||||
|
||||
$data = [
|
||||
'module' => $moduleinfo,
|
||||
'categories' => $categories,
|
||||
'forums' => $forums,
|
||||
'topics' => $topics,
|
||||
'posts' => $posts,
|
||||
];
|
||||
|
||||
MyDumpTool::makeDirectory('src/'.$d3forum);
|
||||
MyDumpTool::makeDirectory('src/'.$d3forum.'/assets');
|
||||
MyDumpTool::saveJson('src/'.$d3forum.'/assets/forum.json', $data);
|
||||
$contents[] = $data;
|
||||
}
|
||||
|
||||
@@ -302,12 +302,12 @@ while ($row = $xoopsDB->fetchArray($res)) {
|
||||
$items[] = $row;
|
||||
|
||||
$simpfurl = '';
|
||||
if ($row['doi'] != '' && isset($simpflink['id'][$row['doi']])) {
|
||||
if ('' != $row['doi'] && isset($simpflink['id'][$row['doi']])) {
|
||||
$simpfurl = $simpflink['id'][$row['doi']];
|
||||
} else if (isset($simpflink['item_id'][$row['item_id']])) {
|
||||
} elseif (isset($simpflink['item_id'][$row['item_id']])) {
|
||||
$simpfurl = $simpflink['item_id'][$row['item_id']];
|
||||
}
|
||||
if ($simpfurl !== '') {
|
||||
if ('' !== $simpfurl) {
|
||||
$simpfurls[] = [
|
||||
'id' => $row['item_id'],
|
||||
'url' => $simpfurl,
|
||||
@@ -376,13 +376,13 @@ while ($row = $xoopsDB->fetchArray($res)) {
|
||||
@mkdir($file_dir);
|
||||
}
|
||||
//if (!file_exists($file_dir.'/'.$file_name)) {
|
||||
if (!MyDumpTool::fileCopy($src_file, $file_dir.'/'.$file_name)) {
|
||||
echo 'failed to copy file: '.$basePath.'/'.$file_id.PHP_EOL;
|
||||
}
|
||||
$htaccess = $file_dir.'/.htaccess';
|
||||
$xfilename = str_replace(' ', '\\ ', $file_name);
|
||||
$data = "RewriteEngine On\nRewriteBase /database/file/$file_id\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteRule .* $xfilename [R=301,L]\n";
|
||||
file_put_contents($htaccess, $data);
|
||||
if (!MyDumpTool::fileCopy($src_file, $file_dir.'/'.$file_name)) {
|
||||
echo 'failed to copy file: '.$basePath.'/'.$file_id.PHP_EOL;
|
||||
}
|
||||
$htaccess = $file_dir.'/.htaccess';
|
||||
$xfilename = str_replace(' ', '\\ ', $file_name);
|
||||
$data = "RewriteEngine On\nRewriteBase /database/file/$file_id\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteRule .* $xfilename [R=301,L]\n";
|
||||
file_put_contents($htaccess, $data);
|
||||
//}
|
||||
if ('preview' == $file_type) {
|
||||
$thumbnail_file = $file_dir.'.png';
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import React from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import { MultiLang } from '../config';
|
||||
import Config, { MultiLang } from '../config';
|
||||
import D3Forum from '../d3forum/D3Forum';
|
||||
import D3ForumXoopsPathRedirect from '../d3forum/D3ForumXoopsPathRedirect';
|
||||
import Database from '../database/Database';
|
||||
import Forum from '../forum/Forum';
|
||||
import DatabaseXoopsPathRedirect from '../database/DatabaseXoopsPathRedirect';
|
||||
import About from './About';
|
||||
import XoopsPathRedirect from './XoopsPathRedirect';
|
||||
|
||||
@@ -11,12 +13,19 @@ interface Props {
|
||||
}
|
||||
|
||||
const MainContent = (props: Props) => {
|
||||
const { lang } = props;
|
||||
return (
|
||||
<div className="mainContent">
|
||||
<Switch>
|
||||
<Route path="/database" render={() => <Database {...props} />} />
|
||||
<Route path="/forum" render={() => <Forum {...props} />} />
|
||||
<Route exact path="/about" render={() => <About {...props} />} />
|
||||
<Route path="/database" render={() => <Database lang={lang} />} />
|
||||
{Config.D3FORUM_MODULES.map((name) =>
|
||||
<Route key={name} path={'/' + name} render={() => <D3Forum lang={lang} name={name} />} />
|
||||
)}
|
||||
<Route exact path="/about" render={() => <About lang={lang} />} />
|
||||
<Route path="/modules/xoonips" render={() => <DatabaseXoopsPathRedirect lang={lang} />} />
|
||||
{Config.D3FORUM_MODULES.map((name) =>
|
||||
<Route key={name} path={'/modules/' + name} render={() => <D3ForumXoopsPathRedirect lang={lang} name={name} />} />
|
||||
)}
|
||||
<Route component={XoopsPathRedirect} />
|
||||
</Switch>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Redirect, RouteComponentProps } from 'react-router';
|
||||
import { MultiLang } from '../config';
|
||||
import funcs from '../functions';
|
||||
import PageNotFound from './lib/PageNotFound';
|
||||
|
||||
interface Params {
|
||||
@@ -16,149 +15,11 @@ interface Props extends RouteComponentProps<Params> {
|
||||
class XoopsPathRedirect extends Component<Props> {
|
||||
|
||||
getRedirectUrl() {
|
||||
const { pathname, hash } = this.props.location;
|
||||
const query = new URLSearchParams(this.props.location.search);
|
||||
const { pathname } = this.props.location;
|
||||
switch (pathname || '') {
|
||||
case '/index.php': {
|
||||
return '/';
|
||||
}
|
||||
case '/modules/xoonips':
|
||||
case '/modules/xoonips/index.php': {
|
||||
return '/database';
|
||||
}
|
||||
case '/modules/xoonips/detail.php': {
|
||||
const id = query.get('id');
|
||||
if (id !== null) {
|
||||
return '/database/item/id/' + funcs.escape(id);
|
||||
}
|
||||
const itemId = query.get('item_id');
|
||||
if (itemId !== null && itemId.match(/^\d+$/) !== null) {
|
||||
return '/database/item/' + funcs.escape(itemId);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
case '/modules/xoonips/listitem.php': {
|
||||
const indexId = query.get('index_id');
|
||||
if (indexId !== null && indexId.match(/^\d+$/) !== null) {
|
||||
const params = new URLSearchParams();
|
||||
const map: any = {
|
||||
orderby: { key: 'orderby', isNumber: false },
|
||||
order_dir: { key: 'order_dir', isNumber: true },
|
||||
itemcount: { key: 'itemcount', isNumber: true },
|
||||
page: { key: 'page', isNumber: true }
|
||||
};
|
||||
for (let k in map) {
|
||||
const v = query.get(k);
|
||||
if (v === null || v.length === 0) {
|
||||
continue;
|
||||
}
|
||||
if (map[k].isNumber && v.match(/^\d+$/) !== null) {
|
||||
continue;
|
||||
}
|
||||
params.set(map[k].key, v);
|
||||
}
|
||||
const paramStr = params.toString();
|
||||
return '/database/list/' + funcs.escape(indexId) + (paramStr.length > 0 ? '?' + paramStr : '');
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '/modules/xoonips/itemselect.php': {
|
||||
const op = query.get('op');
|
||||
if (op === null) {
|
||||
break;
|
||||
}
|
||||
switch (op) {
|
||||
case 'quicksearch': {
|
||||
const keyword = query.get('keyword');
|
||||
const itemType = query.get('search_itemtype');
|
||||
if (keyword === null || itemType === null || keyword === '') {
|
||||
return '';
|
||||
}
|
||||
const type = itemType.replace('xnp', '');
|
||||
if (itemType !== 'basic' && itemType !== 'all' && itemType.match(/^xnp.+/) === null) {
|
||||
return '';
|
||||
}
|
||||
const params = new URLSearchParams({ type, keyword });
|
||||
const map: any = {
|
||||
orderby: { key: 'orderby', isNumber: false },
|
||||
orderdir: { key: 'order_dir', isNumber: true },
|
||||
item_per_page: { key: 'itemcount', isNumber: true },
|
||||
page: { key: 'page', isNumber: true }
|
||||
};
|
||||
for (let k in map) {
|
||||
const v = query.get(k);
|
||||
if (v === null || v.length === 0) {
|
||||
continue;
|
||||
}
|
||||
if (map[k].isNumber && v.match(/^\d+$/) !== null) {
|
||||
continue;
|
||||
}
|
||||
params.set(map[k].key, v);
|
||||
}
|
||||
return '/database/search?' + params.toString();
|
||||
}
|
||||
case 'itemtypesearch': {
|
||||
const itemType = query.get('search_itemtype');
|
||||
if (itemType === null || itemType.match(/^xnp.+/) === null) {
|
||||
return '';
|
||||
}
|
||||
const type = itemType.replace('xnp', '');
|
||||
return '/database/search/itemtype/' + funcs.escape(type);
|
||||
}
|
||||
case 'itemsubtypesearch': {
|
||||
let type = '';
|
||||
let subtype = '';
|
||||
query.forEach((v, k) => {
|
||||
if (k.match(/^xnp[a-z]+$/) !== null && !!v) {
|
||||
type = k.replace('xnp', '');
|
||||
return;
|
||||
}
|
||||
})
|
||||
if (type === '') {
|
||||
return '';
|
||||
}
|
||||
query.forEach((v, k) => {
|
||||
if (k.match(`^xnp${type}_.+$`) !== null && !!v) {
|
||||
subtype = v;
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (subtype === '') {
|
||||
return '';
|
||||
}
|
||||
return '/database/search/itemtype/' + funcs.escape(type) + '/' + funcs.escape(subtype);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
case '/modules/xoonips/advanced_search.php': {
|
||||
return '/database/advanced';
|
||||
}
|
||||
case '/modules/forum':
|
||||
case '/modules/forum/index.php': {
|
||||
const catId = query.get('cat_id');
|
||||
if (catId !== null && catId.match(/^\d+$/) !== null) {
|
||||
return '/forum/category/' + funcs.escape(catId);
|
||||
}
|
||||
const forumId = query.get('forum_id');
|
||||
if (forumId !== null && forumId.match(/^\d+$/) !== null) {
|
||||
return '/forum/forum/' + funcs.escape(forumId);
|
||||
}
|
||||
const topicId = query.get('topic_id');
|
||||
if (topicId !== null && topicId.match(/^\d+$/) !== null) {
|
||||
const matches = hash.match(/^#post_id(\d+)$/);
|
||||
return '/forum/topic/' + funcs.escape(topicId) + (matches === null ? '' : '#postId' + matches[1]);
|
||||
}
|
||||
const postId = query.get('post_id');
|
||||
if (postId !== null && postId.match(/^\d+$/) !== null) {
|
||||
return '/forum/post/' + funcs.escape(postId);
|
||||
}
|
||||
const catIds = query.get('cat_ids');
|
||||
if (catIds !== null && catIds.match(/^\d+$/) !== null) {
|
||||
return '/forum/category/' + funcs.escape(catIds);
|
||||
}
|
||||
return '/forum/';
|
||||
}
|
||||
case '/modules/contact':
|
||||
case '/modules/mailform':
|
||||
case '/modules/mailform/index.php': {
|
||||
|
||||
@@ -2,6 +2,7 @@ const SITE_TITLE = '[en]CBSN platform[/en][ja]包括脳プラットフォーム[
|
||||
const SITE_SLOGAN = 'XooNIps for CBSN';
|
||||
const GOOGLE_ANALYTICS_TRACKING_ID = 'UA-2780809-1';
|
||||
const XOONIPS_ITEMTYPES = ['tool', 'paper', 'presentation', 'book', 'data', 'url', 'files'];
|
||||
const D3FORUM_MODULES = ['forum'];
|
||||
|
||||
export type MultiLang = 'en' | 'ja';
|
||||
|
||||
@@ -10,6 +11,7 @@ const Config = {
|
||||
SITE_SLOGAN,
|
||||
GOOGLE_ANALYTICS_TRACKING_ID,
|
||||
XOONIPS_ITEMTYPES,
|
||||
D3FORUM_MODULES,
|
||||
}
|
||||
|
||||
export default Config;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { Route, RouteComponentProps, Switch } from 'react-router-dom';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import './assets/d3forum_common.css';
|
||||
import './assets/d3forum_main.css';
|
||||
import D3ForumCategory from './D3ForumCategory';
|
||||
import D3ForumForum from './D3ForumForum';
|
||||
import D3ForumPost from './D3ForumPost';
|
||||
import D3ForumTop from './D3ForumTop';
|
||||
import D3ForumTopic from './D3ForumTopic';
|
||||
import D3ForumUtils from './lib/D3ForumUtils';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const D3Forum = (props: Props) => {
|
||||
const { lang, name } = props;
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{D3ForumUtils.getTitle(name, lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<Switch>
|
||||
<Route exact path={'/' + name} render={() => <D3ForumTop {...props} />} />
|
||||
<Route exact path={'/' + name + '/category/:id'} render={(props: RouteComponentProps<{ id: string }>) => <D3ForumCategory lang={lang} name={name} {...props} />} />
|
||||
<Route exact path={'/' + name + '/forum/:id'} render={(props: RouteComponentProps<{ id: string }>) => <D3ForumForum lang={lang} name={name} {...props} />} />
|
||||
<Route exact path={'/' + name + '/topic/:id'} render={(props: RouteComponentProps<{ id: string }>) => <D3ForumTopic lang={lang} name={name} {...props} />} />
|
||||
<Route exact path={'/' + name + '/post/:id'} render={(props: RouteComponentProps<{ id: string }>) => <D3ForumPost lang={lang} name={name} {...props} />} />
|
||||
<Route component={PageNotFound} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default D3Forum;
|
||||
@@ -11,7 +11,7 @@ import imageCategory1 from './assets/images/category_1.gif';
|
||||
import imageForum0 from './assets/images/forum_0.gif';
|
||||
import imageForum1 from './assets/images/forum_1.gif';
|
||||
import CategoryJump from './lib/CategoryJump';
|
||||
import ForumUtils, { ForumCategoryData, ForumForumData } from './lib/ForumUtils';
|
||||
import D3ForumUtils, { D3ForumCategoryData, D3ForumForumData } from './lib/D3ForumUtils';
|
||||
import PostIcon from './lib/PostIcon';
|
||||
|
||||
interface Params {
|
||||
@@ -19,22 +19,24 @@ interface Params {
|
||||
}
|
||||
interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface ForumCategoryProps {
|
||||
interface D3ForumCategoryProps {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
catId: number;
|
||||
}
|
||||
|
||||
const ForumCategorySubCategory = (props: ForumCategoryProps) => {
|
||||
const { lang, catId } = props;
|
||||
const D3ForumCategorySubCategory = (props: D3ForumCategoryProps) => {
|
||||
const { lang, name, catId } = props;
|
||||
const LABEL_HEADER_TITLE = Functions.mlang('[en]Subcategories[/en][ja]サブカテゴリ[/ja]', lang);
|
||||
const LABEL_TOTAL_TOPICS = Functions.mlang('[en]Total topics[/en][ja]総トピック数[/ja]', lang);
|
||||
const LABEL_TOTAL_POSTS = Functions.mlang('[en]Total posts[/en][ja]総投稿数[/ja]', lang);
|
||||
const LABEL_LATEST_POST = Functions.mlang('[en]Latest post[/en][ja]最新投稿[/ja]', lang);
|
||||
const subCategories = ForumUtils.getSubCategories(catId).map((category: ForumCategoryData) => {
|
||||
const subCategories = D3ForumUtils.getSubCategories(name, catId).map((category: D3ForumCategoryData) => {
|
||||
const title = Functions.mlang(category.cat_title, lang);
|
||||
const url = ForumUtils.getCategoryUrl(category.cat_id);
|
||||
const url = D3ForumUtils.getCategoryUrl(name, category.cat_id);
|
||||
const image = category.cat_posts_count === 0 ? imageCategory0 : imageCategory1;
|
||||
const latest = category.cat_last_post_time === 0 ? '' : ', ' + LABEL_LATEST_POST + ': ' + moment(new Date(category.cat_last_post_time * 1000)).format('Y/M/D H:m');
|
||||
return (
|
||||
@@ -58,8 +60,8 @@ const ForumCategorySubCategory = (props: ForumCategoryProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
const ForumCategoryForum = (props: ForumCategoryProps) => {
|
||||
const { lang, catId } = props;
|
||||
const D3ForumCategoryForum = (props: D3ForumCategoryProps) => {
|
||||
const { lang, name, catId } = props;
|
||||
const LABEL_HEADER_TITLE = Functions.mlang('[en]Forum[/en][ja]フォーラム[/ja]', lang);
|
||||
const LABEL_FORUM = Functions.mlang('[en]Forum[/en][ja]フォーラム[/ja]', lang);
|
||||
const LABEL_TOPICS = Functions.mlang('[en]Topics[/en][ja]トピック数[/ja]', lang);
|
||||
@@ -67,14 +69,14 @@ const ForumCategoryForum = (props: ForumCategoryProps) => {
|
||||
const LABEL_LATEST_POST = Functions.mlang('[en]Latest post[/en][ja]最新投稿[/ja]', lang);
|
||||
const LABEL_NEW_POSTS = Functions.mlang('[en]New posts[/en][ja]新しい投稿があります[/ja]', lang);
|
||||
const LABEL_NO_NEW_POSTS = Functions.mlang('[en]No new posts[/en][ja]新しい投稿はありません[/ja]', lang);
|
||||
const forums = ForumUtils.getForums(catId).map((forum: ForumForumData, idx: number) => {
|
||||
const forums = D3ForumUtils.getForums(name, catId).map((forum: D3ForumForumData, idx: number) => {
|
||||
const evenodd = idx % 2 === 0 ? 'even' : 'odd';
|
||||
const title = Functions.mlang(forum.forum_title, lang);
|
||||
const desc = Functions.mlang(forum.forum_desc, lang);
|
||||
const url = ForumUtils.getForumUrl(forum.forum_id);
|
||||
const url = D3ForumUtils.getForumUrl(name, forum.forum_id);
|
||||
const image = forum.forum_posts_count === 0 ? imageForum0 : imageForum1;
|
||||
const getPoster = (postId: number) => {
|
||||
const post = ForumUtils.getPost(postId);
|
||||
const post = D3ForumUtils.getPost(name, postId);
|
||||
if (post === null) {
|
||||
return null;
|
||||
}
|
||||
@@ -84,7 +86,7 @@ const ForumCategoryForum = (props: ForumCategoryProps) => {
|
||||
{moment(new Date(post.post_time * 1000)).format('Y/M/D H:m')}<br />
|
||||
{post.uid_uname}
|
||||
|
||||
<Link to={ForumUtils.getPostUrl(post.post_id)}>
|
||||
<Link to={D3ForumUtils.getPostUrl(name, post.post_id)}>
|
||||
<PostIcon lang={lang} post={post} title={subject} />
|
||||
</Link>
|
||||
</>
|
||||
@@ -138,14 +140,14 @@ const ForumCategoryForum = (props: ForumCategoryProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
const ForumCategory = (props: Props) => {
|
||||
const { lang } = props;
|
||||
const D3ForumCategory = (props: Props) => {
|
||||
const { lang, name } = props;
|
||||
const params = props.match.params;
|
||||
if (params.id === '') {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const catId = parseInt(props.match.params.id, 10);
|
||||
const category = ForumUtils.getCategory(catId);
|
||||
const category = D3ForumUtils.getCategory(name, catId);
|
||||
if (category === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
@@ -153,17 +155,17 @@ const ForumCategory = (props: Props) => {
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{title} - {ForumUtils.getTitle(lang)} - {Functions.siteTitle(lang)}</title>
|
||||
<title>{title} - {D3ForumUtils.getTitle(name, lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<div className="d3f_breadcrumbs">
|
||||
<Link to={ForumUtils.getIndexUrl()}>{Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang)}</Link>
|
||||
<Link to={D3ForumUtils.getIndexUrl(name)}>{Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang)}</Link>
|
||||
</div>
|
||||
<h1 className="d3f_title">{title}</h1>
|
||||
<ForumCategorySubCategory lang={lang} catId={catId} />
|
||||
<ForumCategoryForum lang={lang} catId={catId} />
|
||||
<CategoryJump lang={lang} catId={catId} />
|
||||
<D3ForumCategorySubCategory lang={lang} name={name} catId={catId} />
|
||||
<D3ForumCategoryForum lang={lang} name={name} catId={catId} />
|
||||
<CategoryJump lang={lang} name={name} catId={catId} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ForumCategory;
|
||||
export default D3ForumCategory;
|
||||
@@ -15,7 +15,7 @@ import imageTopicStatusMarked1 from './assets/images/topic_status_marked1.gif';
|
||||
import imageTopicStatusSolved0 from './assets/images/topic_status_solved0.gif';
|
||||
import imageTopicSticky0 from './assets/images/topic_sticky0.gif';
|
||||
import ForumJump from './lib/ForumJump';
|
||||
import ForumUtils, { ForumPostData, ForumPostSortOrder, ForumTopicData } from './lib/ForumUtils';
|
||||
import D3ForumUtils, { D3ForumPostData, D3ForumPostSortOrder, D3ForumTopicData } from './lib/D3ForumUtils';
|
||||
import PostIcon from './lib/PostIcon';
|
||||
|
||||
interface Params {
|
||||
@@ -23,34 +23,35 @@ interface Params {
|
||||
}
|
||||
interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const ForumForum = (props: Props) => {
|
||||
const { lang } = props;
|
||||
const D3ForumForum = (props: Props) => {
|
||||
const { lang, name } = props;
|
||||
const params = props.match.params;
|
||||
if (params.id === '') {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const forumId = parseInt(props.match.params.id, 10);
|
||||
const forum = ForumUtils.getForum(forumId);
|
||||
const forum = D3ForumUtils.getForum(name, forumId);
|
||||
if (forum === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const category = ForumUtils.getCategory(forum.cat_id);
|
||||
const category = D3ForumUtils.getCategory(name, forum.cat_id);
|
||||
if (category === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const topics = ForumUtils.getTopics(forum.forum_id);
|
||||
const topics = D3ForumUtils.getTopics(name, forum.forum_id);
|
||||
const title = Functions.mlang(forum.forum_title, lang);
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{title} - {ForumUtils.getTitle(lang)} - {Functions.siteTitle(lang)}</title>
|
||||
<title>{title} - {D3ForumUtils.getTitle(name, lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<div className="d3f_breadcrumbs">
|
||||
<HashLink to={ForumUtils.getIndexUrl()}>{Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang)}</HashLink>
|
||||
<HashLink to={D3ForumUtils.getIndexUrl(name)}>{Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang)}</HashLink>
|
||||
>
|
||||
<HashLink to={ForumUtils.getCategoryUrl(category.cat_id)}>{Functions.mlang(category.cat_title, lang)}</HashLink>
|
||||
<HashLink to={D3ForumUtils.getCategoryUrl(name, category.cat_id)}>{Functions.mlang(category.cat_title, lang)}</HashLink>
|
||||
</div>
|
||||
<h1 className="d3f_title">{title}</h1>
|
||||
<p className="d3f_welcome">{Functions.mlang(forum.forum_desc, lang)}</p>
|
||||
@@ -64,21 +65,21 @@ const ForumForum = (props: Props) => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{topics.map((topic: ForumTopicData, idx: number) => {
|
||||
const postStart = ForumUtils.getPost(topic.topic_first_post_id);
|
||||
const postLast = ForumUtils.getPost(topic.topic_last_post_id);
|
||||
{topics.map((topic: D3ForumTopicData, idx: number) => {
|
||||
const postStart = D3ForumUtils.getPost(name, topic.topic_first_post_id);
|
||||
const postLast = D3ForumUtils.getPost(name, topic.topic_last_post_id);
|
||||
if (postStart === null || postLast === null) {
|
||||
return null;
|
||||
}
|
||||
const postTitleStart = Functions.mlang(postStart.subject, lang);
|
||||
const imageTopic = topic.topic_invisible !== 0 ? imageTopicInvisible : topic.topic_sticky !== 0 ? imageTopicSticky0 : imageTopic10;
|
||||
const evenodd = idx % 2 === 0 ? 'even' : 'odd';
|
||||
const poster = (post: ForumPostData) => {
|
||||
const poster = (post: D3ForumPostData) => {
|
||||
const title = Functions.mlang(post.subject, lang);
|
||||
return (
|
||||
<>
|
||||
{moment(new Date(post.post_time * 1000)).format('YYYY/M/D')}<br />
|
||||
{post.uid_uname} <HashLink to={ForumUtils.getPostUrl(post.post_id)}><PostIcon lang={lang} post={post} title={title} /></HashLink>
|
||||
{post.uid_uname} <HashLink to={D3ForumUtils.getPostUrl(name, post.post_id)}><PostIcon lang={lang} post={post} title={title} /></HashLink>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -90,7 +91,7 @@ const ForumForum = (props: Props) => {
|
||||
<td className="d3f_topictitle">
|
||||
{topic.topic_solved === 0 && <img src={imageTopicStatusSolved0} alt="" />}
|
||||
{topic.topic_locked !== 0 && <img src={imageTopicStatusLocked1} alt="" />}
|
||||
<HashLink to={ForumUtils.getTopicUrl(topic.topic_id, ForumPostSortOrder.TREE, postLast.post_id)}>{postTitleStart}</HashLink>
|
||||
<HashLink to={D3ForumUtils.getTopicUrl(name, topic.topic_id, D3ForumPostSortOrder.TREE, postLast.post_id)}>{postTitleStart}</HashLink>
|
||||
</td>
|
||||
<td>{topic.topic_posts_count - 1}</td>
|
||||
<td className="d3f_posters">
|
||||
@@ -118,9 +119,9 @@ const ForumForum = (props: Props) => {
|
||||
<li><img src={imageTopicStatusMarked1} alt="" width="18" height="18" /> = {Functions.mlang('[en]Marked[/en][ja]未解決トピック[/ja]', lang)}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ForumJump lang={lang} forumId={forum.forum_id} />
|
||||
<ForumJump lang={lang} name={name} forumId={forum.forum_id} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ForumForum;
|
||||
export default D3ForumForum;
|
||||
@@ -0,0 +1,80 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import ForumJump from './lib/ForumJump';
|
||||
import D3ForumUtils, { D3ForumPostSortOrder, D3ForumPostData } from './lib/D3ForumUtils';
|
||||
import Post from './lib/Post';
|
||||
import PostsTree from './lib/PostsTree';
|
||||
|
||||
interface Params {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const D3ForumPost = (props: Props) => {
|
||||
const { lang, name } = props;
|
||||
const params = props.match.params;
|
||||
if (params.id === '') {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const postId = parseInt(props.match.params.id, 10);
|
||||
const post = D3ForumUtils.getPost(name, postId);
|
||||
if (post === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const topic = D3ForumUtils.getTopic(name, post.topic_id);
|
||||
if (topic === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const forum = D3ForumUtils.getForum(name, topic.forum_id);
|
||||
if (forum === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const category = D3ForumUtils.getCategory(name, forum.cat_id);
|
||||
if (category === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const posts = D3ForumUtils.getPosts(name, topic.topic_id, D3ForumPostSortOrder.TREE);
|
||||
const idx = posts.findIndex((post: D3ForumPostData) => {
|
||||
return post.post_id === postId;
|
||||
});
|
||||
const prevPostId = idx <= 0 ? 0 : posts[idx - 1].post_id;
|
||||
const nextPostId = (idx + 1) === posts.length ? 0 : posts[idx + 1].post_id;
|
||||
const title = Functions.mlang(post.subject, lang);
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{title} - {D3ForumUtils.getTitle(name, lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<div className="d3f_breadcrumbs">
|
||||
<Link to={D3ForumUtils.getIndexUrl(name)}>{Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang)}</Link>
|
||||
>
|
||||
<Link to={D3ForumUtils.getCategoryUrl(name, category.cat_id)}>{Functions.mlang(category.cat_title, lang)}</Link>
|
||||
>
|
||||
<Link to={D3ForumUtils.getForumUrl(name, forum.forum_id)}>{Functions.mlang(forum.forum_title, lang)}</Link>
|
||||
>
|
||||
<Link to={D3ForumUtils.getTopicUrl(name, topic.topic_id, D3ForumPostSortOrder.TREE, null)}>{Functions.mlang(topic.topic_title, lang)}</Link>
|
||||
</div>
|
||||
<h1 className="d3f_title">{title}</h1>
|
||||
<PostsTree lang={lang} name={name} posts={posts} postId={postId} />
|
||||
<br />
|
||||
<p className="d3f_topicinfo">
|
||||
<Link to={D3ForumUtils.getTopicUrl(name, topic.topic_id, D3ForumPostSortOrder.TREE, null)}>{Functions.mlang('[en]List posts in the topic[/en][ja]このトピックの投稿一覧へ[/ja]', lang)}</Link>
|
||||
</p>
|
||||
<div className="d3f_wrap">
|
||||
<Post lang={lang} name={name} post={post} prevPostId={prevPostId} nextPostId={nextPostId} inTopic={false} />
|
||||
</div>
|
||||
<ForumJump lang={lang} name={name} forumId={forum.forum_id} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default D3ForumPost;
|
||||
@@ -8,29 +8,32 @@ import imageCategory1 from './assets/images/category_1.gif';
|
||||
import imageForum0 from './assets/images/forum_0.gif';
|
||||
import imageForum1 from './assets/images/forum_1.gif';
|
||||
import ForumJump from './lib/ForumJump';
|
||||
import ForumUtils, { ForumCategoryData, ForumForumData } from './lib/ForumUtils';
|
||||
import D3ForumUtils, { D3ForumCategoryData, D3ForumForumData } from './lib/D3ForumUtils';
|
||||
import XoopsCode from '../common/lib/XoopsCode';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
|
||||
export interface Props {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface ForumTopSubCategoryProps extends Props {
|
||||
interface D3ForumTopSubCategoryProps extends Props {
|
||||
catId: number;
|
||||
}
|
||||
|
||||
interface ForumTopForumProps extends Props {
|
||||
interface D3ForumTopForumProps extends Props {
|
||||
catId: number;
|
||||
}
|
||||
|
||||
const ForumTopForum = (props: ForumTopForumProps) => {
|
||||
const { catId, lang } = props;
|
||||
const D3ForumTopForum = (props: D3ForumTopForumProps) => {
|
||||
const { lang, name, catId } = props;
|
||||
const LABEL_HEADER_TITLE = Functions.mlang('[en]Forum[/en][ja]フォーラム[/ja]', lang);
|
||||
const LABEL_TOPICS = Functions.mlang('[en]Topics[/en][ja]トピック数[/ja]', lang);
|
||||
const LABEL_POSTS = Functions.mlang('[en]Posts[/en][ja]投稿数[/ja]', lang);
|
||||
const LABEL_LATEST_POST = Functions.mlang('[en]Latest post[/en][ja]最新投稿[/ja]', lang);
|
||||
const forums = ForumUtils.getForums(catId).map((forum: ForumForumData) => {
|
||||
const forums = D3ForumUtils.getForums(name, catId).map((forum: D3ForumForumData) => {
|
||||
const title = Functions.mlang(forum.forum_title, lang);
|
||||
const url = ForumUtils.getForumUrl(forum.forum_id);
|
||||
const url = D3ForumUtils.getForumUrl(name, forum.forum_id);
|
||||
const image = forum.forum_posts_count === 0 ? imageForum0 : imageForum1;
|
||||
const latest = forum.forum_last_post_time === 0 ? '' : ', ' + LABEL_LATEST_POST + ': ' + moment(new Date(forum.forum_last_post_time * 1000)).format('Y/M/D H:m');
|
||||
return (
|
||||
@@ -54,15 +57,15 @@ const ForumTopForum = (props: ForumTopForumProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
const ForumTopSubCategory = (props: ForumTopSubCategoryProps) => {
|
||||
const { catId, lang } = props;
|
||||
const D3ForumTopSubCategory = (props: D3ForumTopSubCategoryProps) => {
|
||||
const { lang, name, catId } = props;
|
||||
const LABEL_HEADER_TITLE = Functions.mlang('[en]Subcategories[/en][ja]サブカテゴリ[/ja]', lang);
|
||||
const LABEL_TOTAL_TOPICS = Functions.mlang('[en]Total topics[/en][ja]総トピック数[/ja]', lang);
|
||||
const LABEL_TOTAL_POSTS = Functions.mlang('[en]Total posts[/en][ja]総投稿数[/ja]', lang);
|
||||
const LABEL_LATEST_POST = Functions.mlang('[en]Latest post[/en][ja]最新投稿[/ja]', lang);
|
||||
const subCategories = ForumUtils.getSubCategories(catId).map((category: ForumCategoryData) => {
|
||||
const subCategories = D3ForumUtils.getSubCategories(name, catId).map((category: D3ForumCategoryData) => {
|
||||
const title = Functions.mlang(category.cat_title, lang);
|
||||
const url = ForumUtils.getCategoryUrl(category.cat_id);
|
||||
const url = D3ForumUtils.getCategoryUrl(name, category.cat_id);
|
||||
const image = category.cat_posts_count === 0 ? imageCategory0 : imageCategory1;
|
||||
const latest = category.cat_last_post_time === 0 ? '' : ', ' + LABEL_LATEST_POST + ': ' + moment(new Date(category.cat_last_post_time * 1000)).format('Y/M/D H:m');
|
||||
return (
|
||||
@@ -86,15 +89,15 @@ const ForumTopSubCategory = (props: ForumTopSubCategoryProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
const ForumTopCategory = (props: Props) => {
|
||||
const { lang } = props;
|
||||
const D3ForumTopCategory = (props: Props) => {
|
||||
const { lang, name } = props;
|
||||
const LABEL_TOTAL_TOPICS = Functions.mlang('[en]Total topics[/en][ja]総トピック数[/ja]', lang);
|
||||
const LABEL_TOTAL_POSTS = Functions.mlang('[en]Total posts[/en][ja]総投稿数[/ja]', lang);
|
||||
const LABEL_LATEST_POST = Functions.mlang('[en]Latest post[/en][ja]最新投稿[/ja]', lang);
|
||||
const categories = ForumUtils.getCategories().map((category: ForumCategoryData) => {
|
||||
const categories = D3ForumUtils.getCategories(name).map((category: D3ForumCategoryData) => {
|
||||
const title = Functions.mlang(category.cat_title, lang);
|
||||
const image = category.cat_posts_count === 0 ? imageCategory0 : imageCategory1;
|
||||
const url = ForumUtils.getCategoryUrl(category.cat_id);
|
||||
const url = D3ForumUtils.getCategoryUrl(name, category.cat_id);
|
||||
const latest = category.cat_last_post_time === 0 ? '' : ', ' + LABEL_LATEST_POST + ': ' + moment(new Date(category.cat_last_post_time * 1000)).format('Y/M/D H:m');
|
||||
return (
|
||||
<Fragment key={category.cat_id}>
|
||||
@@ -104,8 +107,8 @@ const ForumTopCategory = (props: Props) => {
|
||||
</h2>
|
||||
<p>{LABEL_TOTAL_TOPICS}: {category.cat_topics_count}, {LABEL_TOTAL_POSTS}: {category.cat_posts_count}{latest}</p>
|
||||
</div>
|
||||
<ForumTopSubCategory lang={lang} catId={category.cat_id} />
|
||||
<ForumTopForum lang={lang} catId={category.cat_id} />
|
||||
<D3ForumTopSubCategory lang={lang} name={name} catId={category.cat_id} />
|
||||
<D3ForumTopForum lang={lang} name={name} catId={category.cat_id} />
|
||||
<div className="d3f_info_ctrl">
|
||||
</div>
|
||||
</Fragment>
|
||||
@@ -121,25 +124,26 @@ const ForumTopCategory = (props: Props) => {
|
||||
);
|
||||
}
|
||||
|
||||
const ForumTop = (props: Props) => {
|
||||
const { lang } = props;
|
||||
const D3ForumTop = (props: Props) => {
|
||||
const { lang, name } = props;
|
||||
const LABEL_TOTAL_TOPICS = Functions.mlang('[en]Total topics:[/en][ja]総トピック数:[/ja]', lang);
|
||||
const LABEL_TOTAL_POSTS = Functions.mlang('[en]Total posts:[/en][ja]総投稿数:[/ja]', lang);
|
||||
const LABEL_NEW_POSTS = Functions.mlang('[en]New posts[/en][ja]新しい投稿があります[/ja]', lang);
|
||||
const LABEL_NO_NEW_POSTS = Functions.mlang('[en]No new posts[/en][ja]新しい投稿はありません[/ja]', lang);
|
||||
const totalTopics = ForumUtils.getTotalTopics();
|
||||
const totalPosts = ForumUtils.getTotalPosts();
|
||||
const d3forum = D3ForumUtils.getModule(name);
|
||||
if (d3forum === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<h1 className="d3f_title">フォーラムトップ</h1>
|
||||
<p className="d3f_welcome">興味のあるフォーラムへぜひご参加ください</p>
|
||||
<XoopsCode lang={lang} text={d3forum.message} dohtml={true} />
|
||||
<dl className="d3f_bbsinfo">
|
||||
<dt>{LABEL_TOTAL_TOPICS} </dt>
|
||||
<dd>{totalTopics}, </dd>
|
||||
<dd>{D3ForumUtils.getTotalTopics(name)}, </dd>
|
||||
<dt>{LABEL_TOTAL_POSTS} </dt>
|
||||
<dd>{totalPosts}</dd>
|
||||
<dd>{D3ForumUtils.getTotalPosts(name)}</dd>
|
||||
</dl>
|
||||
<ForumTopCategory lang={lang} />
|
||||
<D3ForumTopCategory lang={lang} name={name} />
|
||||
<div className="d3f_iconexps clearfix">
|
||||
<ul className="d3f_iconexp">
|
||||
<li><img src={imageForum1} alt="" width="18" height="18" /> = {LABEL_NEW_POSTS}</li>
|
||||
@@ -149,9 +153,9 @@ const ForumTop = (props: Props) => {
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ForumJump lang={lang} forumId={0} />
|
||||
<ForumJump lang={lang} name={name} forumId={0} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ForumTop;
|
||||
export default D3ForumTop;
|
||||
@@ -0,0 +1,125 @@
|
||||
import React, { Component } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { HashLink } from 'react-router-hash-link';
|
||||
import Loading from '../common/lib/Loading';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import D3ForumUtils, { D3ForumCategoryData, D3ForumForumData, D3ForumPostData, D3ForumPostSortOrder, D3ForumTopicData } from './lib/D3ForumUtils';
|
||||
import ForumJump from './lib/ForumJump';
|
||||
import Post from './lib/Post';
|
||||
import PostsTree from './lib/PostsTree';
|
||||
|
||||
interface Params {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface State {
|
||||
loading: boolean;
|
||||
name: string;
|
||||
topicId: number;
|
||||
order: D3ForumPostSortOrder;
|
||||
}
|
||||
|
||||
class D3ForumTopic extends Component<Props, State> {
|
||||
|
||||
private topic: D3ForumTopicData | null = null;
|
||||
private forum: D3ForumForumData | null = null;
|
||||
private category: D3ForumCategoryData | null = null;
|
||||
private posts: D3ForumPostData[] = [];
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { name } = props;
|
||||
this.state = {
|
||||
loading: true,
|
||||
name: name,
|
||||
topicId: 0,
|
||||
order: D3ForumPostSortOrder.TREE,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||
const params = new URLSearchParams(nextProps.location.search);
|
||||
const topicId = parseInt(nextProps.match.params.id, 10);
|
||||
const order_ = params.get('order');
|
||||
const order = (order_ !== null && order_.match(/(0|1|2)/)) ? parseInt(order_, 10) as D3ForumPostSortOrder : D3ForumPostSortOrder.TREE;
|
||||
if (nextProps.name !== prevState.name || prevState.topicId !== topicId || prevState.order !== order) {
|
||||
return { loading: true, name: nextProps.name, topicId, order };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.load();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.load();
|
||||
}
|
||||
|
||||
load() {
|
||||
const { name } = this.props;
|
||||
if (this.state.loading) {
|
||||
this.topic = D3ForumUtils.getTopic(name, this.state.topicId);
|
||||
this.forum = D3ForumUtils.getForum(name, this.topic === null ? 0 : this.topic.forum_id);
|
||||
this.category = D3ForumUtils.getCategory(name, this.forum === null ? 0 : this.forum.cat_id);
|
||||
this.posts = D3ForumUtils.getPosts(name, this.state.topicId, this.state.order);
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang, name } = this.props;
|
||||
if (this.state.loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
if (this.topic === null || this.forum === null || this.category === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const orderCtrl = (
|
||||
<div className="clearfix">
|
||||
<div className="d3f_order_ctrl">
|
||||
{this.state.order !== D3ForumPostSortOrder.TREE && <HashLink to={D3ForumUtils.getTopicUrl(name, this.topic.topic_id, D3ForumPostSortOrder.TREE, null)}>{Functions.mlang('[en]Tree order[/en][ja]ツリー構造順で表示[/ja]', lang)}</HashLink>}
|
||||
{this.state.order !== D3ForumPostSortOrder.OLD && <HashLink to={D3ForumUtils.getTopicUrl(name, this.topic.topic_id, D3ForumPostSortOrder.OLD, null)}>{Functions.mlang('[en]Older is upper[/en][ja]投稿の古いものから[/ja]', lang)}</HashLink>}
|
||||
{this.state.order !== D3ForumPostSortOrder.NEW && <HashLink to={D3ForumUtils.getTopicUrl(name, this.topic.topic_id, D3ForumPostSortOrder.NEW, null)}>{Functions.mlang('[en]Newer is upper[/en][ja]投稿の新しいものから[/ja]', lang)}</HashLink>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
const title = Functions.mlang(this.topic.topic_title, lang);
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{title} - {D3ForumUtils.getTitle(name, lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<div className="d3f_breadcrumbs">
|
||||
<HashLink to={D3ForumUtils.getIndexUrl(name)}>{Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang)}</HashLink>
|
||||
>
|
||||
<HashLink to={D3ForumUtils.getCategoryUrl(name, this.category.cat_id)}>{Functions.mlang(this.category.cat_title, lang)}</HashLink>
|
||||
>
|
||||
<HashLink to={D3ForumUtils.getForumUrl(name, this.forum.forum_id)}>{Functions.mlang(this.forum.forum_title, lang)}</HashLink>
|
||||
</div>
|
||||
<h1 className="d3f_title">{title}</h1>
|
||||
<PostsTree lang={lang} name={name} posts={this.posts} postId={0} />
|
||||
{orderCtrl}
|
||||
<div className="d3f_wrap">
|
||||
{this.posts.map((post, idx) => {
|
||||
const prevPostId = idx === 0 ? 0 : this.posts[idx - 1].post_id;
|
||||
const nextPostId = (idx + 1) === this.posts.length ? 0 : this.posts[idx + 1].post_id;
|
||||
return <Post key={post.post_id} lang={lang} name={name} post={post} prevPostId={prevPostId} nextPostId={nextPostId} inTopic={true} />;
|
||||
})}
|
||||
</div>
|
||||
{orderCtrl}
|
||||
<ForumJump lang={lang} name={name} forumId={this.forum.forum_id} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default D3ForumTopic;
|
||||
@@ -0,0 +1,65 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Redirect, RouteComponentProps, withRouter } from 'react-router';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
}
|
||||
|
||||
class D3ForumXoopsPathRedirect extends Component<Props> {
|
||||
|
||||
getRedirectUrl(): string {
|
||||
const { name, location } = this.props;
|
||||
const pathname = location.pathname || '';
|
||||
const hash = location.hash || '';
|
||||
const query = new URLSearchParams(location.search);
|
||||
const search = new RegExp(`^/modules/${name}(?:/+(.*))?$`);
|
||||
const matches = pathname.match(search);
|
||||
if (matches === null) {
|
||||
return '';
|
||||
}
|
||||
const path = matches[1] || '';
|
||||
switch (path) {
|
||||
case '':
|
||||
case 'index.php': {
|
||||
const catId = query.get('cat_id');
|
||||
if (catId !== null && catId.match(/^\d+$/) !== null) {
|
||||
return '/' + name + '/category/' + Functions.escape(catId);
|
||||
}
|
||||
const forumId = query.get('forum_id');
|
||||
if (forumId !== null && forumId.match(/^\d+$/) !== null) {
|
||||
return '/' + name + '/forum/' + Functions.escape(forumId);
|
||||
}
|
||||
const topicId = query.get('topic_id');
|
||||
if (topicId !== null && topicId.match(/^\d+$/) !== null) {
|
||||
const matches = hash.match(/^#post_id(\d+)$/);
|
||||
return '/' + name + '/topic/' + Functions.escape(topicId) + (matches === null ? '' : '#postId' + matches[1]);
|
||||
}
|
||||
const postId = query.get('post_id');
|
||||
if (postId !== null && postId.match(/^\d+$/) !== null) {
|
||||
return '/' + name + '/post/' + Functions.escape(postId);
|
||||
}
|
||||
const catIds = query.get('cat_ids');
|
||||
if (catIds !== null && catIds.match(/^\d+$/) !== null) {
|
||||
return '/' + name + '/category/' + Functions.escape(catIds);
|
||||
}
|
||||
return '/' + name + '/';
|
||||
}
|
||||
}
|
||||
return '/' + name + '/' + path;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const url = this.getRedirectUrl();
|
||||
if (url === '') {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
return <Redirect to={url} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(D3ForumXoopsPathRedirect);
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1010 B After Width: | Height: | Size: 1010 B |
|
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 189 B |
|
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 189 B |
|
Before Width: | Height: | Size: 190 B After Width: | Height: | Size: 190 B |
|
Before Width: | Height: | Size: 190 B After Width: | Height: | Size: 190 B |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 127 B After Width: | Height: | Size: 127 B |
|
Before Width: | Height: | Size: 97 B After Width: | Height: | Size: 97 B |
|
Before Width: | Height: | Size: 137 B After Width: | Height: | Size: 137 B |
|
Before Width: | Height: | Size: 906 B After Width: | Height: | Size: 906 B |
|
Before Width: | Height: | Size: 878 B After Width: | Height: | Size: 878 B |
|
Before Width: | Height: | Size: 881 B After Width: | Height: | Size: 881 B |
|
Before Width: | Height: | Size: 643 B After Width: | Height: | Size: 643 B |
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 544 B |
|
Before Width: | Height: | Size: 523 B After Width: | Height: | Size: 523 B |
|
Before Width: | Height: | Size: 540 B After Width: | Height: | Size: 540 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -2,35 +2,36 @@ import React from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||
import { MultiLang } from '../../config';
|
||||
import Functions from '../../functions';
|
||||
import ForumUtils, { ForumCategoryData } from './ForumUtils';
|
||||
import D3ForumUtils, { D3ForumCategoryData } from './D3ForumUtils';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
catId: number;
|
||||
}
|
||||
|
||||
export const CategoryJump = (props: Props) => {
|
||||
const { lang, catId } = props;
|
||||
const { lang, name, catId } = props;
|
||||
const LABEL_TOP = Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang);
|
||||
const LABE_SUBMIT = Functions.mlang('[en]Jump to a category[/en][ja]カテゴリージャンプ[/ja]', lang);
|
||||
const catSelect = React.createRef<HTMLSelectElement>();
|
||||
const catSelectOptions: JSX.Element[] = [
|
||||
<option key="0" value="0">({LABEL_TOP})</option>
|
||||
];
|
||||
const catSelectLoop = (categories: ForumCategoryData[]) => {
|
||||
const catSelectLoop = (categories: D3ForumCategoryData[]) => {
|
||||
categories.forEach((category) => {
|
||||
const title = Functions.mlang(category.cat_title, lang);
|
||||
const depth = category.cat_depth_in_tree !== 0 ? '--'.repeat(category.cat_depth_in_tree) + ' ' : '';
|
||||
catSelectOptions.push(<option key={category.cat_id} value={category.cat_id}>{depth}{title}</option>);
|
||||
catSelectLoop(ForumUtils.getSubCategories(category.cat_id));
|
||||
catSelectLoop(D3ForumUtils.getSubCategories(name, category.cat_id));
|
||||
});
|
||||
};
|
||||
catSelectLoop(ForumUtils.getCategories());
|
||||
catSelectLoop(D3ForumUtils.getCategories(name));
|
||||
return (<form className="d3f_form" onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
if (catSelect.current !== null) {
|
||||
const catId = parseInt(catSelect.current.value, 10)
|
||||
const url = catId === 0 ? ForumUtils.getIndexUrl() : ForumUtils.getCategoryUrl(catId);
|
||||
const url = catId === 0 ? D3ForumUtils.getIndexUrl(name) : D3ForumUtils.getCategoryUrl(name, catId);
|
||||
props.history.push(url);
|
||||
}
|
||||
}}>
|
||||
@@ -0,0 +1,399 @@
|
||||
import loki from 'lokijs';
|
||||
import { MultiLang } from '../../config';
|
||||
import Functions from '../../functions';
|
||||
import d3forumJson from '../assets/d3forum.json';
|
||||
|
||||
export interface D3ForumModuleData {
|
||||
name: string;
|
||||
dirname: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface D3ForumCategoryData {
|
||||
cat_id: number;
|
||||
pid: number;
|
||||
cat_title: string;
|
||||
cat_desc: string;
|
||||
cat_topics_count: number;
|
||||
cat_posts_count: number;
|
||||
cat_last_post_id: number;
|
||||
cat_last_post_time: number;
|
||||
cat_topics_count_in_tree: number;
|
||||
cat_posts_count_in_tree: number;
|
||||
cat_last_post_id_in_tree: number;
|
||||
cat_last_post_time_in_tree: number;
|
||||
cat_depth_in_tree: number;
|
||||
cat_order_in_tree: number;
|
||||
cat_path_in_tree: any;
|
||||
cat_unique_path: string;
|
||||
cat_weight: number;
|
||||
cat_options: any;
|
||||
}
|
||||
|
||||
export interface D3ForumForumData {
|
||||
forum_id: number;
|
||||
cat_id: number;
|
||||
forum_external_link_format: string;
|
||||
forum_title: string;
|
||||
forum_desc: string;
|
||||
forum_topics_count: number;
|
||||
forum_posts_count: number;
|
||||
forum_last_post_id: number;
|
||||
forum_last_post_time: number;
|
||||
forum_weight: number;
|
||||
forum_options: any;
|
||||
}
|
||||
|
||||
export interface D3ForumTopicData {
|
||||
topic_id: number;
|
||||
forum_id: number;
|
||||
topic_external_link_id: string;
|
||||
topic_title: string;
|
||||
topic_first_uid: number;
|
||||
topic_first_post_id: number;
|
||||
topic_first_post_time: number;
|
||||
topic_last_uid: number;
|
||||
topic_last_post_id: number;
|
||||
topic_last_post_time: number;
|
||||
topic_views: number;
|
||||
topic_posts_count: number;
|
||||
topic_locked: number;
|
||||
topic_sticky: number;
|
||||
topic_solved: number;
|
||||
topic_invisible: number;
|
||||
topic_votes_sum: number;
|
||||
topic_votes_count: number;
|
||||
topic_first_uid_name: string;
|
||||
topic_first_uid_uname: string;
|
||||
topic_last_uid_name: string;
|
||||
topic_last_uid_uname: string;
|
||||
}
|
||||
|
||||
export interface D3ForumPostData {
|
||||
post_id: number;
|
||||
pid: number;
|
||||
topic_id: number;
|
||||
post_time: number;
|
||||
modified_time: number;
|
||||
uid: number;
|
||||
uid_hidden: number;
|
||||
poster_ip: string;
|
||||
modifier_ip: string;
|
||||
subject: string;
|
||||
subject_waiting: string;
|
||||
html: number;
|
||||
smiley: number;
|
||||
xcode: number;
|
||||
br: number;
|
||||
number_entity: number;
|
||||
special_entity: number;
|
||||
icon: number;
|
||||
attachsig: number;
|
||||
invisible: number;
|
||||
approval: number;
|
||||
votes_sum: number;
|
||||
votes_count: number;
|
||||
depth_in_tree: number;
|
||||
order_in_tree: number;
|
||||
path_in_tree: string;
|
||||
unique_path: string;
|
||||
guest_name: string;
|
||||
post_text: string;
|
||||
post_text_waiting: string;
|
||||
uid_name: string;
|
||||
uid_uname: string;
|
||||
uid_rank: number;
|
||||
uid_posts: number;
|
||||
}
|
||||
|
||||
interface D3ForumData {
|
||||
module: D3ForumModuleData;
|
||||
categories: D3ForumCategoryData[];
|
||||
forums: D3ForumForumData[];
|
||||
topics: D3ForumTopicData[];
|
||||
posts: D3ForumPostData[];
|
||||
}
|
||||
|
||||
interface D3ForumLokiData {
|
||||
module: D3ForumModuleData;
|
||||
categories: Collection<D3ForumCategoryData>;
|
||||
forums: Collection<D3ForumForumData>;
|
||||
topics: Collection<D3ForumTopicData>;
|
||||
posts: Collection<D3ForumPostData>;
|
||||
}
|
||||
|
||||
const categorySort = (a: D3ForumCategoryData, b: D3ForumCategoryData) => {
|
||||
if (a.cat_weight > b.cat_weight) {
|
||||
return 1;
|
||||
} else if (a.cat_weight < b.cat_weight) {
|
||||
return -1;
|
||||
}
|
||||
if (a.cat_id > b.cat_id) {
|
||||
return 1;
|
||||
} else if (a.cat_id < b.cat_id) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const forumSort = (a: D3ForumForumData, b: D3ForumForumData) => {
|
||||
if (a.forum_weight > b.forum_weight) {
|
||||
return 1;
|
||||
} else if (a.forum_weight < b.forum_weight) {
|
||||
return -1;
|
||||
}
|
||||
if (a.forum_id > b.forum_id) {
|
||||
return 1;
|
||||
} else if (a.forum_id < b.forum_id) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
export enum D3ForumPostSortOrder { TREE, OLD, NEW }
|
||||
class D3ForumPostSorter {
|
||||
|
||||
private order: D3ForumPostSortOrder;
|
||||
|
||||
constructor(order: D3ForumPostSortOrder) {
|
||||
this.order = order;
|
||||
this.sort = this.sort.bind(this);
|
||||
}
|
||||
|
||||
sort(a: D3ForumPostData, b: D3ForumPostData) {
|
||||
switch (this.order) {
|
||||
case D3ForumPostSortOrder.TREE: {
|
||||
if (a.unique_path > b.unique_path) {
|
||||
return 1;
|
||||
} else if (a.unique_path < b.unique_path) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case D3ForumPostSortOrder.OLD: {
|
||||
if (a.post_time > b.post_time) {
|
||||
return 1;
|
||||
} else if (a.post_time < b.post_time) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case D3ForumPostSortOrder.NEW: {
|
||||
if (a.post_time > b.post_time) {
|
||||
return -1;
|
||||
} else if (a.post_time < b.post_time) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class D3ForumUtils {
|
||||
|
||||
private database: loki;
|
||||
private modules: Map<string, D3ForumLokiData>;
|
||||
|
||||
constructor(json: D3ForumData[]) {
|
||||
this.database = new loki('d3forum');
|
||||
this.modules = new Map<string, D3ForumLokiData>();
|
||||
json.forEach((data) => {
|
||||
const name = data.module.dirname;
|
||||
const d3forum = {
|
||||
module: data.module,
|
||||
categories: this.database.addCollection<D3ForumCategoryData>(name + '_categories'),
|
||||
forums: this.database.addCollection<D3ForumForumData>(name + '_forums'),
|
||||
topics: this.database.addCollection<D3ForumTopicData>(name + '_topics'),
|
||||
posts: this.database.addCollection<D3ForumPostData>(name + '_posts'),
|
||||
}
|
||||
data.categories.forEach((category) => {
|
||||
d3forum.categories.insert(category);
|
||||
});
|
||||
data.forums.forEach((forum) => {
|
||||
d3forum.forums.insert(forum);
|
||||
});
|
||||
data.topics.forEach((topic) => {
|
||||
d3forum.topics.insert(topic);
|
||||
});
|
||||
data.posts.forEach((post) => {
|
||||
d3forum.posts.insert(post);
|
||||
});
|
||||
this.modules.set(name, d3forum);
|
||||
});
|
||||
}
|
||||
|
||||
getTitle(name: string, lang: MultiLang): string {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return '';
|
||||
}
|
||||
return Functions.mlang(d3forum.module.name, lang);
|
||||
}
|
||||
|
||||
getIndexUrl(name: string): string {
|
||||
return '/' + name;
|
||||
}
|
||||
|
||||
getCategoryUrl(name: string, catId: number): string {
|
||||
return this.getIndexUrl(name) + '/category/' + catId;
|
||||
}
|
||||
|
||||
getForumUrl(name: string, forumId: number): string {
|
||||
return this.getIndexUrl(name) + '/forum/' + forumId;
|
||||
}
|
||||
|
||||
getTopicUrl(name: string, topicId: number, order: D3ForumPostSortOrder, postId: number | null): string {
|
||||
const params = new URLSearchParams();
|
||||
if (order !== D3ForumPostSortOrder.TREE) {
|
||||
params.set('order', String(order));
|
||||
}
|
||||
const paramString = params.toString();
|
||||
return this.getIndexUrl(name) + '/topic/' + topicId + (paramString !== '' ? '?' + paramString : '') + (postId !== null ? '#postId' + postId : '');
|
||||
}
|
||||
|
||||
getPostUrl(name: string, postId: number): string {
|
||||
return this.getIndexUrl(name) + '/post/' + postId;
|
||||
}
|
||||
|
||||
getTotalTopics(name: string): number {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return 0;
|
||||
}
|
||||
return d3forum.topics.count();
|
||||
}
|
||||
|
||||
getTotalPosts(name: string): number {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return 0;
|
||||
}
|
||||
return d3forum.posts.count();
|
||||
}
|
||||
|
||||
getModule(name: string): D3ForumModuleData | null{
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
return d3forum.module;
|
||||
}
|
||||
|
||||
getCategories(name: string): D3ForumCategoryData[] {
|
||||
return this.getSubCategories(name, 0);
|
||||
}
|
||||
|
||||
getSubCategories(name: string, parentCatId: number): D3ForumCategoryData[] {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
const filter = {
|
||||
'pid': parentCatId
|
||||
};
|
||||
const result = d3forum.categories.chain().find(filter).sort(categorySort).data();
|
||||
return result;
|
||||
}
|
||||
|
||||
getCategory(name: string, catId: number): D3ForumCategoryData | null {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
const filter = {
|
||||
'cat_id': catId
|
||||
};
|
||||
const result = d3forum.categories.findOne(filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
getForums(name: string, catId: number): D3ForumForumData[] {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
const filter = {
|
||||
'cat_id': catId
|
||||
};
|
||||
const result = d3forum.forums.chain().find(filter).sort(forumSort).data();
|
||||
return result;
|
||||
}
|
||||
|
||||
getForum(name: string, forumId: number): D3ForumForumData | null {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
const filter = {
|
||||
'forum_id': forumId
|
||||
};
|
||||
const result = d3forum.forums.findOne(filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
getTopics(name: string, forumId: number): D3ForumTopicData[] {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
const filter = {
|
||||
'forum_id': forumId
|
||||
};
|
||||
const result = d3forum.topics.find(filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
getTopic(name: string, topicId: number): D3ForumTopicData | null {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
const filter = {
|
||||
'topic_id': topicId
|
||||
};
|
||||
const result = d3forum.topics.findOne(filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
getPosts(name: string, topicId: number, order: D3ForumPostSortOrder): D3ForumPostData[] {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
const filter = {
|
||||
'topic_id': topicId
|
||||
};
|
||||
const sorter = new D3ForumPostSorter(order);
|
||||
const result = d3forum.posts.chain().find(filter).sort(sorter.sort).data();
|
||||
return result;
|
||||
}
|
||||
|
||||
getChildPosts(name: string, parentPostId: number): D3ForumPostData[] {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return [];
|
||||
}
|
||||
const filter = {
|
||||
'pid': parentPostId
|
||||
};
|
||||
const sorter = new D3ForumPostSorter(D3ForumPostSortOrder.TREE);
|
||||
const result = d3forum.posts.chain().find(filter).sort(sorter.sort).data();
|
||||
return result;
|
||||
}
|
||||
|
||||
getPost(name: string, postId: number): D3ForumPostData | null {
|
||||
const d3forum = this.modules.get(name);
|
||||
if (typeof d3forum === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
const filter = {
|
||||
'post_id': postId
|
||||
};
|
||||
const result = d3forum.posts.findOne(filter);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export default new D3ForumUtils(d3forumJson);
|
||||
@@ -2,34 +2,35 @@ import React from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||
import { MultiLang } from '../../config';
|
||||
import Functions from '../../functions';
|
||||
import ForumUtils, { ForumCategoryData, ForumForumData } from './ForumUtils';
|
||||
import D3ForumUtils, { D3ForumCategoryData, D3ForumForumData } from './D3ForumUtils';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
name: string;
|
||||
forumId: number;
|
||||
}
|
||||
|
||||
export const ForumJump = (props: Props) => {
|
||||
const { lang, forumId } = props;
|
||||
const { lang, name, forumId } = props;
|
||||
const LABE_SUBMIT = Functions.mlang('[en]Jump to a forum[/en][ja]フォーラムジャンプ[/ja]', lang);
|
||||
const forumSelect = React.createRef<HTMLSelectElement>();
|
||||
const forumSelectOptions: JSX.Element[] = [];
|
||||
const forumSelectLoop = (categories: ForumCategoryData[]) => {
|
||||
const forumSelectLoop = (categories: D3ForumCategoryData[]) => {
|
||||
categories.forEach((category) => {
|
||||
ForumUtils.getForums(category.cat_id).forEach((forum: ForumForumData) => {
|
||||
D3ForumUtils.getForums(name, category.cat_id).forEach((forum: D3ForumForumData) => {
|
||||
const title = Functions.mlang(category.cat_title + ' - ' + forum.forum_title, lang);
|
||||
const depth = category.cat_depth_in_tree !== 0 ? '--'.repeat(category.cat_depth_in_tree) + ' ' : '';
|
||||
forumSelectOptions.push(<option key={forum.forum_id} value={forum.forum_id}>{depth}{title}</option>);
|
||||
});
|
||||
forumSelectLoop(ForumUtils.getSubCategories(category.cat_id));
|
||||
forumSelectLoop(D3ForumUtils.getSubCategories(name, category.cat_id));
|
||||
});
|
||||
};
|
||||
forumSelectLoop(ForumUtils.getCategories());
|
||||
forumSelectLoop(D3ForumUtils.getCategories(name));
|
||||
return (
|
||||
<form className="d3f_form" onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
if (forumSelect.current !== null) {
|
||||
const url = ForumUtils.getForumUrl(parseInt(forumSelect.current.value, 10));
|
||||
const url = D3ForumUtils.getForumUrl(name, parseInt(forumSelect.current.value, 10));
|
||||
props.history.push(url);
|
||||
}
|
||||
}}>
|
||||
@@ -6,27 +6,28 @@ import UserRankStarImage from '../../common/lib/UserRankStarImage';
|
||||
import XoopsCode from '../../common/lib/XoopsCode';
|
||||
import { MultiLang } from '../../config';
|
||||
import Functions from '../../functions';
|
||||
import ForumUtils, { ForumPostData } from './ForumUtils';
|
||||
import D3ForumUtils, { D3ForumPostData } from './D3ForumUtils';
|
||||
import PostIcon from './PostIcon';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
post: ForumPostData;
|
||||
name: string;
|
||||
post: D3ForumPostData;
|
||||
nextPostId: number;
|
||||
prevPostId: number;
|
||||
inTopic: boolean;
|
||||
}
|
||||
|
||||
const postUrl = (postId: number, inTopic: boolean) => {
|
||||
return inTopic ? '#postId' + postId : ForumUtils.getPostUrl(postId);
|
||||
const postUrl = (name: string, postId: number, inTopic: boolean) => {
|
||||
return inTopic ? '#postId' + postId : D3ForumUtils.getPostUrl(name, postId);
|
||||
}
|
||||
|
||||
const Post = (props: Props) => {
|
||||
const { lang, post, nextPostId, prevPostId, inTopic } = props;
|
||||
const { lang, name, post, nextPostId, prevPostId, inTopic } = props;
|
||||
const depth = String(post.depth_in_tree * 5) + '%';
|
||||
const url = ForumUtils.getPostUrl(post.post_id)
|
||||
const url = D3ForumUtils.getPostUrl(name, post.post_id)
|
||||
const subject = <><PostIcon lang={lang} post={post} /> {Functions.mlang(post.subject, lang)}</>;
|
||||
const children = ForumUtils.getChildPosts(post.post_id);
|
||||
const children = D3ForumUtils.getChildPosts(name, post.post_id);
|
||||
const LABEL_PARENT = Functions.mlang('[en]Parent[/en][ja]親投稿[/ja]', lang);
|
||||
const LABEL_PREV = Functions.mlang('[en]Previous post[/en][ja]前の投稿[/ja]', lang);
|
||||
const LABEL_NEXT = Functions.mlang('[en]Next post[/en][ja]次の投稿[/ja]', lang);
|
||||
@@ -47,23 +48,21 @@ const Post = (props: Props) => {
|
||||
<dd>{post.depth_in_tree}</dd>
|
||||
</dl>
|
||||
<div className="d3f_info_val">
|
||||
{prevPostId === 0 ? LABEL_PREV : <HashLink to={postUrl(prevPostId, inTopic)}>{LABEL_PREV}</HashLink>}
|
||||
{prevPostId === 0 ? LABEL_PREV : <HashLink to={postUrl(name, prevPostId, inTopic)}>{LABEL_PREV}</HashLink>}
|
||||
-
|
||||
{nextPostId === 0 ? LABEL_NEXT : <HashLink to={postUrl(nextPostId, inTopic)}>{LABEL_NEXT}</HashLink>}
|
||||
{nextPostId === 0 ? LABEL_NEXT : <HashLink to={postUrl(name, nextPostId, inTopic)}>{LABEL_NEXT}</HashLink>}
|
||||
|
|
||||
{post.pid === 0 ? LABEL_PARENT : <HashLink to={postUrl(post.pid, inTopic)}>{LABEL_PARENT}</HashLink>}
|
||||
{post.pid === 0 ? LABEL_PARENT : <HashLink to={postUrl(name, post.pid, inTopic)}>{LABEL_PARENT}</HashLink>}
|
||||
-
|
||||
{children.length === 0 ? LABEL_NO_CHILD : children.map(
|
||||
(child, idx) => {
|
||||
const label = (idx === 0 ? LABEL_CHILD : '') + child.unique_path.substr(post.unique_path.length);
|
||||
return (
|
||||
<Fragment key={child.post_id}>
|
||||
{idx > 0 && ' '}
|
||||
<HashLink to={postUrl(child.post_id, inTopic)}>{label}</HashLink>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
)}
|
||||
{children.length === 0 ? LABEL_NO_CHILD : children.map((child: D3ForumPostData, idx: number) => {
|
||||
const label = (idx === 0 ? LABEL_CHILD : '') + child.unique_path.substr(post.unique_path.length);
|
||||
return (
|
||||
<Fragment key={child.post_id}>
|
||||
{idx > 0 && ' '}
|
||||
<HashLink to={postUrl(name, child.post_id, inTopic)}>{label}</HashLink>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
|
|
||||
{Functions.mlang('[en]Posted on[/en][ja]投稿日時[/ja]', lang)} {moment(new Date(post.post_time * 1000)).format('YYYY/M/D H:m')}
|
||||
</div>
|
||||
@@ -9,11 +9,11 @@ import imagePost4 from '../assets/images/posticon4.gif';
|
||||
import imagePost5 from '../assets/images/posticon5.gif';
|
||||
import imagePost6 from '../assets/images/posticon6.gif';
|
||||
import imagePost7 from '../assets/images/posticon7.gif';
|
||||
import { ForumPostData } from './ForumUtils';
|
||||
import { D3ForumPostData } from './D3ForumUtils';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
post: ForumPostData;
|
||||
post: D3ForumPostData;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
@@ -3,21 +3,22 @@ import React from 'react';
|
||||
import { HashLink } from 'react-router-hash-link';
|
||||
import { MultiLang } from '../../config';
|
||||
import Functions from '../../functions';
|
||||
import ForumUtils, { ForumPostData } from './ForumUtils';
|
||||
import D3ForumUtils, { D3ForumPostData } from './D3ForumUtils';
|
||||
import PostIcon from './PostIcon';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
posts: ForumPostData[];
|
||||
name: string;
|
||||
posts: D3ForumPostData[];
|
||||
postId: number;
|
||||
}
|
||||
|
||||
const postUrl = (postId: number, inTopic: boolean) => {
|
||||
return inTopic ? '#postId' + postId : ForumUtils.getPostUrl(postId);
|
||||
const postUrl = (name: string, postId: number, inTopic: boolean) => {
|
||||
return inTopic ? '#postId' + postId : D3ForumUtils.getPostUrl(name, postId);
|
||||
}
|
||||
|
||||
const PostsTree = (props: Props) => {
|
||||
const { lang, posts, postId } = props;
|
||||
const { lang, name, posts, postId } = props;
|
||||
const inTopic = postId === 0;
|
||||
return (
|
||||
<div className="d3f_post_tree">
|
||||
@@ -32,7 +33,7 @@ const PostsTree = (props: Props) => {
|
||||
return (
|
||||
<li key={post.post_id} className={className}>
|
||||
<span style={style}>
|
||||
{post.post_id === postId ? subject : <HashLink to={postUrl(post.post_id, inTopic)}>{subject}</HashLink>}
|
||||
{post.post_id === postId ? subject : <HashLink to={postUrl(name, post.post_id, inTopic)}>{subject}</HashLink>}
|
||||
|
||||
({post.uid !== 0 ? post.uid_uname : post.guest_name}, {moment(new Date(post.post_time * 1000)).format('YYYY/M/D H:mm')})
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { Route, RouteComponentProps, Switch } from 'react-router-dom';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import './assets/d3forum_common.css';
|
||||
import './assets/d3forum_main.css';
|
||||
import ForumCategory from './ForumCategory';
|
||||
import ForumForum from './ForumForum';
|
||||
import ForumPost from './ForumPost';
|
||||
import ForumTop from './ForumTop';
|
||||
import ForumTopic from './ForumTopic';
|
||||
import ForumUtils from './lib/ForumUtils';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
const Forum = (props: Props) => {
|
||||
const { lang } = props;
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{ForumUtils.getTitle(lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<Switch>
|
||||
<Route exact path="/forum" render={() => <ForumTop {...props} />} />
|
||||
<Route exact path="/forum/category/:id" render={(props: RouteComponentProps<{ id: string }>) => <ForumCategory lang={lang} {...props} />} />
|
||||
<Route exact path="/forum/forum/:id" render={(props: RouteComponentProps<{ id: string }>) => <ForumForum lang={lang} {...props} />} />
|
||||
<Route exact path="/forum/topic/:id" render={(props: RouteComponentProps<{ id: string }>) => <ForumTopic lang={lang} {...props} />} />
|
||||
<Route exact path="/forum/post/:id" render={(props: RouteComponentProps<{ id: string }>) => <ForumPost lang={lang} {...props} />} />
|
||||
<Route component={PageNotFound} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Forum;
|
||||
@@ -1,79 +0,0 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import ForumJump from './lib/ForumJump';
|
||||
import ForumUtils, { ForumPostSortOrder, ForumPostData } from './lib/ForumUtils';
|
||||
import Post from './lib/Post';
|
||||
import PostsTree from './lib/PostsTree';
|
||||
|
||||
interface Params {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
const ForumPost = (props: Props) => {
|
||||
const { lang } = props;
|
||||
const params = props.match.params;
|
||||
if (params.id === '') {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const postId = parseInt(props.match.params.id, 10);
|
||||
const post = ForumUtils.getPost(postId);
|
||||
if (post === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const topic = ForumUtils.getTopic(post.topic_id);
|
||||
if (topic === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const forum = ForumUtils.getForum(topic.forum_id);
|
||||
if (forum === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const category = ForumUtils.getCategory(forum.cat_id);
|
||||
if (category === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const posts = ForumUtils.getPosts(topic.topic_id, ForumPostSortOrder.TREE);
|
||||
const idx = posts.findIndex((post: ForumPostData) => {
|
||||
return post.post_id === postId;
|
||||
});
|
||||
const prevPostId = idx <= 0 ? 0 : posts[idx - 1].post_id;
|
||||
const nextPostId = (idx + 1) === posts.length ? 0 : posts[idx + 1].post_id;
|
||||
const title = Functions.mlang(post.subject, lang);
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{title} - {ForumUtils.getTitle(lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<div className="d3f_breadcrumbs">
|
||||
<Link to={ForumUtils.getIndexUrl()}>{Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang)}</Link>
|
||||
>
|
||||
<Link to={ForumUtils.getCategoryUrl(category.cat_id)}>{Functions.mlang(category.cat_title, lang)}</Link>
|
||||
>
|
||||
<Link to={ForumUtils.getForumUrl(forum.forum_id)}>{Functions.mlang(forum.forum_title, lang)}</Link>
|
||||
>
|
||||
<Link to={ForumUtils.getTopicUrl(topic.topic_id, ForumPostSortOrder.TREE, null)}>{Functions.mlang(topic.topic_title, lang)}</Link>
|
||||
</div>
|
||||
<h1 className="d3f_title">{title}</h1>
|
||||
<PostsTree lang={lang} posts={posts} postId={postId} />
|
||||
<br />
|
||||
<p className="d3f_topicinfo">
|
||||
<Link to={ForumUtils.getTopicUrl(topic.topic_id, ForumPostSortOrder.TREE, null)}>{Functions.mlang('[en]List posts in the topic[/en][ja]このトピックの投稿一覧へ[/ja]', lang)}</Link>
|
||||
</p>
|
||||
<div className="d3f_wrap">
|
||||
<Post lang={lang} post={post} prevPostId={prevPostId} nextPostId={nextPostId} inTopic={false} />
|
||||
</div>
|
||||
<ForumJump lang={lang} forumId={forum.forum_id} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ForumPost;
|
||||
@@ -1,120 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { HashLink } from 'react-router-hash-link';
|
||||
import Loading from '../common/lib/Loading';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import ForumJump from './lib/ForumJump';
|
||||
import ForumUtils, { ForumCategoryData, ForumForumData, ForumPostData, ForumPostSortOrder, ForumTopicData } from './lib/ForumUtils';
|
||||
import Post from './lib/Post';
|
||||
import PostsTree from './lib/PostsTree';
|
||||
|
||||
interface Params {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
interface State {
|
||||
loading: boolean;
|
||||
topicId: number;
|
||||
order: ForumPostSortOrder;
|
||||
}
|
||||
|
||||
class ForumTopic extends Component<Props, State> {
|
||||
|
||||
private topic: ForumTopicData | null = null;
|
||||
private forum: ForumForumData | null = null;
|
||||
private category: ForumCategoryData | null = null;
|
||||
private posts: ForumPostData[] = [];
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
topicId: 0,
|
||||
order: ForumPostSortOrder.TREE,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||
const params = new URLSearchParams(nextProps.location.search);
|
||||
const topicId = parseInt(nextProps.match.params.id, 10);
|
||||
const order_ = params.get('order');
|
||||
const order = (order_ !== null && order_.match(/(0|1|2)/)) ? parseInt(order_, 10) as ForumPostSortOrder : ForumPostSortOrder.TREE;
|
||||
if (prevState.topicId !== topicId || prevState.order !== order) {
|
||||
return { loading: true, topicId, order };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.load();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.load();
|
||||
}
|
||||
|
||||
load() {
|
||||
if (this.state.loading) {
|
||||
this.topic = ForumUtils.getTopic(this.state.topicId);
|
||||
this.forum = ForumUtils.getForum(this.topic === null ? 0 : this.topic.forum_id);
|
||||
this.category = ForumUtils.getCategory(this.forum === null ? 0 : this.forum.cat_id);
|
||||
this.posts = ForumUtils.getPosts(this.state.topicId, this.state.order);
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
if (this.state.loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
if (this.topic === null || this.forum === null || this.category === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const orderCtrl = (
|
||||
<div className="clearfix">
|
||||
<div className="d3f_order_ctrl">
|
||||
{this.state.order !== ForumPostSortOrder.TREE && <HashLink to={ForumUtils.getTopicUrl(this.topic.topic_id, ForumPostSortOrder.TREE, null)}>{Functions.mlang('[en]Tree order[/en][ja]ツリー構造順で表示[/ja]', lang)}</HashLink>}
|
||||
{this.state.order !== ForumPostSortOrder.OLD && <HashLink to={ForumUtils.getTopicUrl(this.topic.topic_id, ForumPostSortOrder.OLD, null)}>{Functions.mlang('[en]Older is upper[/en][ja]投稿の古いものから[/ja]', lang)}</HashLink>}
|
||||
{this.state.order !== ForumPostSortOrder.NEW && <HashLink to={ForumUtils.getTopicUrl(this.topic.topic_id, ForumPostSortOrder.NEW, null)}>{Functions.mlang('[en]Newer is upper[/en][ja]投稿の新しいものから[/ja]', lang)}</HashLink>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
const title = Functions.mlang(this.topic.topic_title, lang);
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{title} - {ForumUtils.getTitle(lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<div className="d3f_breadcrumbs">
|
||||
<HashLink to={ForumUtils.getIndexUrl()}>{Functions.mlang('[en]Top[/en][ja]トップ[/ja]', lang)}</HashLink>
|
||||
>
|
||||
<HashLink to={ForumUtils.getCategoryUrl(this.category.cat_id)}>{Functions.mlang(this.category.cat_title, lang)}</HashLink>
|
||||
>
|
||||
<HashLink to={ForumUtils.getForumUrl(this.forum.forum_id)}>{Functions.mlang(this.forum.forum_title, lang)}</HashLink>
|
||||
</div>
|
||||
<h1 className="d3f_title">{title}</h1>
|
||||
<PostsTree lang={lang} posts={this.posts} postId={0} />
|
||||
{orderCtrl}
|
||||
<div className="d3f_wrap">
|
||||
{this.posts.map((post, idx) => {
|
||||
const prevPostId = idx === 0 ? 0 : this.posts[idx - 1].post_id;
|
||||
const nextPostId = (idx + 1) === this.posts.length ? 0 : this.posts[idx + 1].post_id;
|
||||
return <Post key={post.post_id} lang={lang} post={post} prevPostId={prevPostId} nextPostId={nextPostId} inTopic={true} />;
|
||||
})}
|
||||
</div>
|
||||
{orderCtrl}
|
||||
<ForumJump lang={lang} forumId={this.forum.forum_id} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ForumTopic;
|
||||
@@ -1,332 +0,0 @@
|
||||
import loki from 'lokijs';
|
||||
import { MultiLang } from '../../config';
|
||||
import Functions from '../../functions';
|
||||
import forumJson from '../assets/forum.json';
|
||||
|
||||
export interface ForumCategoryData {
|
||||
cat_id: number;
|
||||
pid: number;
|
||||
cat_title: string;
|
||||
cat_desc: string;
|
||||
cat_topics_count: number;
|
||||
cat_posts_count: number;
|
||||
cat_last_post_id: number;
|
||||
cat_last_post_time: number;
|
||||
cat_topics_count_in_tree: number;
|
||||
cat_posts_count_in_tree: number;
|
||||
cat_last_post_id_in_tree: number;
|
||||
cat_last_post_time_in_tree: number;
|
||||
cat_depth_in_tree: number;
|
||||
cat_order_in_tree: number;
|
||||
cat_path_in_tree: any;
|
||||
cat_unique_path: string;
|
||||
cat_weight: number;
|
||||
cat_options: any;
|
||||
}
|
||||
|
||||
export interface ForumForumData {
|
||||
forum_id: number;
|
||||
cat_id: number;
|
||||
forum_external_link_format: string;
|
||||
forum_title: string;
|
||||
forum_desc: string;
|
||||
forum_topics_count: number;
|
||||
forum_posts_count: number;
|
||||
forum_last_post_id: number;
|
||||
forum_last_post_time: number;
|
||||
forum_weight: number;
|
||||
forum_options: any;
|
||||
}
|
||||
|
||||
export interface ForumTopicData {
|
||||
topic_id: number;
|
||||
forum_id: number;
|
||||
topic_external_link_id: string;
|
||||
topic_title: string;
|
||||
topic_first_uid: number;
|
||||
topic_first_post_id: number;
|
||||
topic_first_post_time: number;
|
||||
topic_last_uid: number;
|
||||
topic_last_post_id: number;
|
||||
topic_last_post_time: number;
|
||||
topic_views: number;
|
||||
topic_posts_count: number;
|
||||
topic_locked: number;
|
||||
topic_sticky: number;
|
||||
topic_solved: number;
|
||||
topic_invisible: number;
|
||||
topic_votes_sum: number;
|
||||
topic_votes_count: number;
|
||||
topic_first_uid_name: string;
|
||||
topic_first_uid_uname: string;
|
||||
topic_last_uid_name: string;
|
||||
topic_last_uid_uname: string;
|
||||
}
|
||||
|
||||
export interface ForumPostData {
|
||||
post_id: number;
|
||||
pid: number;
|
||||
topic_id: number;
|
||||
post_time: number;
|
||||
modified_time: number;
|
||||
uid: number;
|
||||
uid_hidden: number;
|
||||
poster_ip: string;
|
||||
modifier_ip: string;
|
||||
subject: string;
|
||||
subject_waiting: string;
|
||||
html: number;
|
||||
smiley: number;
|
||||
xcode: number;
|
||||
br: number;
|
||||
number_entity: number;
|
||||
special_entity: number;
|
||||
icon: number;
|
||||
attachsig: number;
|
||||
invisible: number;
|
||||
approval: number;
|
||||
votes_sum: number;
|
||||
votes_count: number;
|
||||
depth_in_tree: number;
|
||||
order_in_tree: number;
|
||||
path_in_tree: string;
|
||||
unique_path: string;
|
||||
guest_name: string;
|
||||
post_text: string;
|
||||
post_text_waiting: string;
|
||||
uid_name: string;
|
||||
uid_uname: string;
|
||||
uid_rank: number;
|
||||
uid_posts: number;
|
||||
}
|
||||
|
||||
interface ForumData {
|
||||
categories: ForumCategoryData[];
|
||||
forums: ForumForumData[];
|
||||
topics: ForumTopicData[];
|
||||
posts: ForumPostData[];
|
||||
}
|
||||
|
||||
const categorySort = (a: ForumCategoryData, b: ForumCategoryData) => {
|
||||
if (a.cat_weight > b.cat_weight) {
|
||||
return 1;
|
||||
} else if (a.cat_weight < b.cat_weight) {
|
||||
return -1;
|
||||
}
|
||||
if (a.cat_id > b.cat_id) {
|
||||
return 1;
|
||||
} else if (a.cat_id < b.cat_id) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const forumSort = (a: ForumForumData, b: ForumForumData) => {
|
||||
if (a.forum_weight > b.forum_weight) {
|
||||
return 1;
|
||||
} else if (a.forum_weight < b.forum_weight) {
|
||||
return -1;
|
||||
}
|
||||
if (a.forum_id > b.forum_id) {
|
||||
return 1;
|
||||
} else if (a.forum_id < b.forum_id) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
export enum ForumPostSortOrder { TREE, OLD, NEW }
|
||||
class PostSorter {
|
||||
|
||||
private order: ForumPostSortOrder;
|
||||
|
||||
constructor(order: ForumPostSortOrder) {
|
||||
this.order = order;
|
||||
this.sort = this.sort.bind(this);
|
||||
}
|
||||
|
||||
sort(a: ForumPostData, b: ForumPostData) {
|
||||
switch (this.order) {
|
||||
case ForumPostSortOrder.TREE: {
|
||||
if (a.unique_path > b.unique_path) {
|
||||
return 1;
|
||||
} else if (a.unique_path < b.unique_path) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ForumPostSortOrder.OLD: {
|
||||
if (a.post_time > b.post_time) {
|
||||
return 1;
|
||||
} else if (a.post_time < b.post_time) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ForumPostSortOrder.NEW: {
|
||||
if (a.post_time > b.post_time) {
|
||||
return -1;
|
||||
} else if (a.post_time < b.post_time) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class ForumUtils {
|
||||
private database: loki;
|
||||
private categories: Collection<ForumCategoryData>;
|
||||
private forums: Collection<ForumForumData>;
|
||||
private topics: Collection<ForumTopicData>;
|
||||
private posts: Collection<ForumPostData>;
|
||||
private totalTopics: number;
|
||||
private totalPosts: number;
|
||||
|
||||
constructor(json: ForumData) {
|
||||
this.database = new loki('forum');
|
||||
this.categories = this.database.addCollection<ForumCategoryData>('categories');
|
||||
this.forums = this.database.addCollection<ForumForumData>('forums');
|
||||
this.topics = this.database.addCollection<ForumTopicData>('topics');
|
||||
this.posts = this.database.addCollection<ForumPostData>('posts');
|
||||
this.totalTopics = 0;
|
||||
this.totalPosts = 0;
|
||||
this.load(json);
|
||||
}
|
||||
|
||||
load(json: ForumData) {
|
||||
json.categories.forEach((category) => {
|
||||
this.categories.insert(category);
|
||||
});
|
||||
json.forums.forEach((forum) => {
|
||||
this.forums.insert(forum);
|
||||
});
|
||||
this.totalTopics = json.topics.length;
|
||||
json.topics.forEach((topic) => {
|
||||
this.topics.insert(topic);
|
||||
});
|
||||
this.totalPosts = json.posts.length;
|
||||
json.posts.forEach((post) => {
|
||||
this.posts.insert(post);
|
||||
});
|
||||
}
|
||||
|
||||
getTitle(lang: MultiLang) {
|
||||
return Functions.mlang('[en]Forum[/en][ja]フォーラム[/ja]', lang);
|
||||
}
|
||||
|
||||
getIndexUrl() {
|
||||
return '/forum';
|
||||
}
|
||||
|
||||
getCategoryUrl(catId: number) {
|
||||
return this.getIndexUrl() + '/category/' + catId;
|
||||
}
|
||||
|
||||
getForumUrl(forumId: number) {
|
||||
return this.getIndexUrl() + '/forum/' + forumId;
|
||||
}
|
||||
|
||||
getTopicUrl(topicId: number, order: ForumPostSortOrder, postId: number | null) {
|
||||
const params = new URLSearchParams();
|
||||
if (order !== ForumPostSortOrder.TREE) {
|
||||
params.set('order', String(order));
|
||||
}
|
||||
const paramString = params.toString();
|
||||
return this.getIndexUrl() + '/topic/' + topicId + (paramString !== '' ? '?' + paramString : '') + (postId !== null ? '#postId' + postId : '');
|
||||
}
|
||||
|
||||
getPostUrl(postId: number) {
|
||||
return this.getIndexUrl() + '/post/' + postId;
|
||||
}
|
||||
|
||||
getTotalTopics() {
|
||||
return this.totalTopics;
|
||||
}
|
||||
|
||||
getTotalPosts() {
|
||||
return this.totalPosts;
|
||||
}
|
||||
|
||||
getCategories() {
|
||||
return this.getSubCategories(0);
|
||||
}
|
||||
|
||||
getSubCategories(parentCatId: number) {
|
||||
const filter = {
|
||||
'pid': parentCatId
|
||||
};
|
||||
const result = this.categories.chain().find(filter).sort(categorySort).data();
|
||||
return result;
|
||||
}
|
||||
|
||||
getCategory(catId: number) {
|
||||
const filter = {
|
||||
'cat_id': catId
|
||||
};
|
||||
const result = this.categories.findOne(filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
getForums(catId: number) {
|
||||
const filter = {
|
||||
'cat_id': catId
|
||||
};
|
||||
const result = this.forums.chain().find(filter).sort(forumSort).data();
|
||||
return result;
|
||||
}
|
||||
|
||||
getForum(forumId: number) {
|
||||
const filter = {
|
||||
'forum_id': forumId
|
||||
};
|
||||
const result = this.forums.findOne(filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
getTopics(forumId: number) {
|
||||
const filter = {
|
||||
'forum_id': forumId
|
||||
};
|
||||
const result = this.topics.find(filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
getTopic(topicId: number) {
|
||||
const filter = {
|
||||
'topic_id': topicId
|
||||
};
|
||||
const result = this.topics.findOne(filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
getPosts(topicId: number, order: ForumPostSortOrder) {
|
||||
const filter = {
|
||||
'topic_id': topicId
|
||||
};
|
||||
const sorter = new PostSorter(order);
|
||||
const result = this.posts.chain().find(filter).sort(sorter.sort).data();
|
||||
return result;
|
||||
}
|
||||
|
||||
getChildPosts(parentPostId: number) {
|
||||
const filter = {
|
||||
'pid': parentPostId
|
||||
};
|
||||
const sorter = new PostSorter(ForumPostSortOrder.TREE);
|
||||
const result = this.posts.chain().find(filter).sort(sorter.sort).data();
|
||||
return result;
|
||||
}
|
||||
|
||||
getPost(postId: number) {
|
||||
const filter = {
|
||||
'post_id': postId
|
||||
};
|
||||
const result = this.posts.findOne(filter);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export default new ForumUtils(forumJson);
|
||||