revised and updated sources.

This commit is contained in:
Yoshihiro OKUMURA 2023-07-28 22:05:26 +09:00
parent 040eee8240
commit 8f37b9c537
Signed by: orrisroot
GPG Key ID: 470AA444C92904B2
163 changed files with 10291 additions and 12457 deletions

29
.eslintrc.cjs Normal file
View File

@ -0,0 +1,29 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:@typescript-eslint/stylistic-type-checked',
'plugin:react-hooks/recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
],
ignorePatterns: ['dist', '.eslintrc.cjs', 'vite.config.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
settings: {
react: {
version: 'detect',
},
},
};

3
.gitignore vendored
View File

@ -22,3 +22,6 @@
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
# customize
/public/data

8
.prettierrc.json Normal file
View File

@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": true,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "all"
}

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"recommendations": [
"jawandarajbir.react-vscode-extension-pack",
"esbenp.prettier-vscode",
"streetsidesoftware.code-spell-checker"
]
}

12
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Vite Debugger",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000/",
"webRoot": "${workspaceFolder}"
}
]
}

71
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,71 @@
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// Extensions - Code Spell Checker
"cSpell.ignoreWords": ["degu", "Neuroinformatics", "octodon", "RIKEN"],
"cSpell.words": [
"dobr",
"doesn",
"dohtml",
"doimage",
"dosmiley",
"doxcode",
"htmlspecialchars",
"itemcount",
"itemselect",
"itemsubtypesearch",
"itemtype",
"itemtypes",
"itemtypesearch",
"justsystem",
"lightbox",
"listitem",
"lokijs",
"mathematica",
"mday",
"mlang",
"navi",
"orderdir",
"pageview",
"pubmed",
"quicksearch",
"simpf",
"simplesort",
"subitemtype",
"xoonips",
"xoops"
],
// Extensions - HTML
"html.format.wrapLineLength": 0,
// Extentions - Prettier
// - see: .prettierrc.json
// Extentions - Typescript
"javascript.updateImportsOnFileMove.enabled": "always",
"typescript.updateImportsOnFileMove.enabled": "always"
}

40
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,40 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "npm: dev",
"detail": "vite dev",
"type": "npm",
"script": "dev",
"problemMatcher": "$tsc",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
}
},
{
"label": "npm: build",
"detail": "vite build",
"type": "npm",
"script": "build",
"group": "build",
"problemMatcher": "$tsc",
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
}
}
]
}

View File

@ -1,8 +1,8 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="shortcut icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
@ -10,14 +10,21 @@
content="BSI-NI Brain Atlas - This site provides the 3D atlas and the standard MRI template of Degu, Common Marmoset and Japanese Macaque Monkey." content="BSI-NI Brain Atlas - This site provides the 3D atlas and the standard MRI template of Degu, Common Marmoset and Japanese Macaque Monkey."
/> />
<meta name="robots" content="index,follow" /> <meta name="robots" content="index,follow" />
<meta name="keywords" content="neuroinformatics, bsi-ni, brain science, xoonips, database, brain atlas, degu, japanese macaque monkey, common marmoset" /> <meta
<meta name="author" content="BSI-NI and Laboratory for Symbolic Cognitive Development, RIKEN Brain Science Institute" /> name="keywords"
content="neuroinformatics, bsi-ni, brain science, xoonips, database, brain atlas, degu, japanese macaque monkey, common marmoset"
/>
<meta
name="author"
content="BSI-NI and Laboratory for Symbolic Cognitive Development, RIKEN Brain Science Institute"
/>
<meta name="copyright" content="Copyright &copy; 2017" /> <meta name="copyright" content="Copyright &copy; 2017" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<title>BSI-NI Brain Atlas</title> <title>BSI-NI Brain Atlas</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body> </body>
</html> </html>

5515
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +1,58 @@
{ {
"name": "brainatlas", "name": "brainatlas",
"version": "1.0.0",
"private": true, "private": true,
"version": "2.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"format": "prettier --write src/"
},
"dependencies": { "dependencies": {
"@orrisroot/react-html-parser": "^2.1.0", "@orrisroot/react-html-parser": "^2.1.1",
"@testing-library/jest-dom": "^5.16.4", "async-lock": "^1.4.0",
"@testing-library/react": "^13.3.0", "axios": "^1.4.0",
"@testing-library/user-event": "^14.2.0",
"@types/async-lock": "^1.1.5",
"@types/jest": "^28.1.1",
"@types/lokijs": "^1.5.7",
"@types/node": "^17.0.41",
"@types/react": "^18.0.12",
"@types/react-dom": "^18.0.5",
"@types/react-router-dom": "^5.3.3",
"@types/react-router-hash-link": "^2.4.5",
"async-lock": "^1.3.1",
"axios": "^0.27.2",
"lokijs": "^1.5.12", "lokijs": "^1.5.12",
"moment": "^2.29.3", "moment": "^2.29.4",
"rc-tree": "^5.6.5", "node-stdlib-browser": "^1.2.0",
"react": "^18.1.0", "rc-tree": "^5.7.9",
"react": "^18.2.0",
"react-app-polyfill": "^3.0.0", "react-app-polyfill": "^3.0.0",
"react-cookie": "^4.1.1", "react-cookie": "^4.1.1",
"react-dom": "^18.1.0", "react-dom": "^18.2.0",
"react-ga4": "^1.4.1", "react-ga4": "^2.1.0",
"react-helmet-async": "^1.3.0", "react-helmet-async": "^1.3.0",
"react-image-lightbox": "^5.1.4", "react-overlays": "^5.2.1",
"react-overlays": "^5.2.0", "react-router-dom": "^6.14.2",
"react-router-dom": "^6.3.0",
"react-router-hash-link": "^2.4.3", "react-router-hash-link": "^2.4.3",
"react-scripts": "^5.0.1",
"react-spinner-material": "^1.4.0", "react-spinner-material": "^1.4.0",
"typescript": "^4.7.3", "sanitize.css": "^13.0.0",
"web-vitals": "^2.1.4", "xregexp": "^5.1.1",
"xregexp": "^5.1.1" "yet-another-react-lightbox": "^3.11.4"
}, },
"resolutions": { "devDependencies": {
"@svgr/webpack": "^6.2.1" "@types/async-lock": "^1.4.0",
}, "@types/jest": "^29.5.3",
"scripts": { "@types/lokijs": "^1.5.8",
"start": "react-scripts start", "@types/node": "^18.17.1",
"build": "react-scripts build", "@types/react": "^18.2.17",
"test": "react-scripts test", "@types/react-dom": "^18.2.7",
"eject": "react-scripts eject" "@types/react-router-dom": "^5.3.3",
}, "@types/react-router-hash-link": "^2.4.6",
"eslintConfig": { "@types/react-syntax-highlighter": "^15.5.7",
"extends": "react-app" "@typescript-eslint/eslint-plugin": "^6.2.0",
}, "@typescript-eslint/parser": "^6.2.0",
"browserslist": { "@vitejs/plugin-react-swc": "^3.3.2",
"production": [ "eslint": "^8.45.0",
">0.2%", "eslint-plugin-react": "^7.33.0",
"not dead", "eslint-plugin-react-hooks": "^4.6.0",
"not op_mini all", "eslint-plugin-react-refresh": "^0.4.3",
"ie 11" "prettier": "^3.0.0",
], "typescript": "^5.1.6",
"development": [ "vite": "^4.4.7",
"last 1 chrome version", "vite-plugin-node-stdlib-browser": "^0.2.1",
"last 1 firefox version", "vite-plugin-rewrite-all": "^1.0.1"
"last 1 safari version",
"ie 11"
]
} }
} }

View File

@ -1,17 +1,22 @@
RewriteEngine on <IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase / RewriteBase /
RewriteCond %{QUERY_STRING} (^|&)file_id=([0-9]+)($|&) RewriteCond %{QUERY_STRING} (^|&)file_id=([0-9]+)($|&)
RewriteRule ^degu/modules/xoonips/download.php /degu/file/%2? [R=301,L] RewriteRule ^degu/modules/xoonips/download.php /data/degu/file/%2? [R=301,L]
RewriteCond %{QUERY_STRING} (^|&)file_id=([0-9]+)($|&) RewriteCond %{QUERY_STRING} (^|&)file_id=([0-9]+)($|&)
RewriteRule ^jm/modules/xoonips/download.php /jm/file/%2? [R=301,L] RewriteRule ^jm/modules/xoonips/download.php /data/jm/file/%2? [R=301,L]
RewriteCond %{QUERY_STRING} (^|&)file_id=([0-9]+)($|&) RewriteCond %{QUERY_STRING} (^|&)file_id=([0-9]+)($|&)
RewriteRule ^marmoset/modules/xoonips/download.php /marmoset/file/%2? [R=301,L] RewriteRule ^marmoset/modules/xoonips/download.php /data/marmoset/file/%2? [R=301,L]
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d [OR] RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l [OR]
RewriteCond %{REQUEST_FILENAME} -d RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME}index.html !-f RewriteCond %{REQUEST_FILENAME}index.html !-f
RewriteRule . /index.html [L] RewriteRule . /index.html [L]
</IfModule>

View File

@ -1,9 +0,0 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@ -1,26 +1,32 @@
import React, { useEffect, useState } from "react"; import React from 'react';
import { CookiesProvider, useCookies } from "react-cookie";
import ReactGA from "react-ga4"; import { CookiesProvider, useCookies } from 'react-cookie';
import { HelmetProvider } from "react-helmet-async"; import ReactGA from 'react-ga4';
import { BrowserRouter, useLocation } from "react-router-dom"; import { HelmetProvider } from 'react-helmet-async';
import "./App.css"; import { BrowserRouter, useLocation } from 'react-router-dom';
import AppRoot from "./common/AppRoot"; import './App.css';
import Config, { MultiLang } from "./config"; import AppRoot from './common/AppRoot';
import Config, { MultiLang } from './config';
const mlang = ['en', 'ja'] as const;
const isMultiLang = (name: string): name is MultiLang => {
return mlang.some((value) => value === name);
};
const AppMain: React.FC = () => { const AppMain: React.FC = () => {
const [cookies, setCookie] = useCookies(); const [cookies, setCookie] = useCookies();
const [lang, setLang] = useState<MultiLang>(["en", "ja"].includes(cookies.ml_lang) ? cookies.ml_lang : "en"); const typedCookies = cookies as Record<string, string>;
const [lang, setLang] = React.useState<MultiLang>(
isMultiLang(typedCookies?.ml_lang ?? '') ? (cookies.ml_lang as MultiLang) : 'en',
);
const location = useLocation(); const location = useLocation();
useEffect(() => { React.useEffect(() => {
if (Config.GOOGLE_ANALYTICS_TRACKING_ID !== "") {
ReactGA.send("pageview");
}
const params = new URLSearchParams(location.search); const params = new URLSearchParams(location.search);
const ml_lang = params.get("ml_lang"); const ml_lang = params.get('ml_lang');
if (ml_lang != null && ["en", "ja"].includes(ml_lang)) { if (ml_lang != null && ['en', 'ja'].includes(ml_lang)) {
if (cookies.ml_lang !== ml_lang) { if (cookies.ml_lang !== ml_lang) {
setCookie("ml_lang", ml_lang); setCookie('ml_lang', ml_lang);
} }
if (lang !== ml_lang) { if (lang !== ml_lang) {
setLang(ml_lang as MultiLang); setLang(ml_lang as MultiLang);
@ -33,7 +39,7 @@ const AppMain: React.FC = () => {
}; };
const App: React.FC = () => { const App: React.FC = () => {
if (Config.GOOGLE_ANALYTICS_TRACKING_ID !== "") { if (Config.GOOGLE_ANALYTICS_TRACKING_ID.startsWith('G-')) {
ReactGA.initialize(Config.GOOGLE_ANALYTICS_TRACKING_ID); ReactGA.initialize(Config.GOOGLE_ANALYTICS_TRACKING_ID);
} }

View File

@ -1,13 +1,14 @@
import React from "react"; import React from 'react';
import { Helmet } from "react-helmet-async";
import { Route, Routes, useLocation } from "react-router-dom"; import { Helmet } from 'react-helmet-async';
import { BrainAtlasType, MultiLang } from "../config"; import { Route, Routes, useLocation } from 'react-router-dom';
import SiteIndex from "../custom/SiteIndex"; import { BrainAtlasType, MultiLang } from '../config';
import Functions from "../functions"; import SiteIndex from '../custom/SiteIndex';
import Footer from "./Footer"; import Functions from '../functions';
import Header from "./Header"; import Footer from './Footer';
import PageNotFound from "./lib/PageNotFound"; import Header from './Header';
import MainContent from "./MainContent"; import MainContent from './MainContent';
import PageNotFound from './lib/PageNotFound';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -19,7 +20,7 @@ interface PropsMain extends Props {
isLink: boolean; isLink: boolean;
} }
const PageMain: React.FC<PropsMain> = (props: PropsMain) => { const PageMain: React.FC<PropsMain> = (props) => {
const { lang, type, isHtml, isLink } = props; const { lang, type, isHtml, isLink } = props;
return ( return (
<> <>
@ -32,10 +33,12 @@ const PageMain: React.FC<PropsMain> = (props: PropsMain) => {
); );
}; };
const AppRoot: React.FC<Props> = (props: Props) => { const AppRoot: React.FC<Props> = (props) => {
const { lang } = props; const { lang } = props;
const location = useLocation(); const location = useLocation();
const match = location.pathname.match(/^\/(degu|jm|marmoset)(?:\/|$|(?:_(html)(?:\/$|$|\/(link\.html$))))/); const match = location.pathname.match(
/^\/(degu|jm|marmoset)(?:\/|$|(?:_(html)(?:\/$|$|\/(link\.html$))))/,
);
const isHtml = match !== null ? typeof match[2] !== 'undefined' : false; const isHtml = match !== null ? typeof match[2] !== 'undefined' : false;
const isLink = match !== null ? typeof match[3] !== 'undefined' : false; const isLink = match !== null ? typeof match[3] !== 'undefined' : false;
@ -48,12 +51,30 @@ const AppRoot: React.FC<Props> = (props: Props) => {
</Helmet> </Helmet>
<Routes> <Routes>
<Route index element={<SiteIndex lang={lang} />} /> <Route index element={<SiteIndex lang={lang} />} />
<Route path="degu_html/*" element={<PageMain lang={lang} type="degu" isHtml={isHtml} isLink={isLink} />} /> <Route
<Route path="jm_html/*" element={<PageMain lang={lang} type="jm" isHtml={isHtml} isLink={isLink} />} /> path="degu_html/*"
<Route path="marmoset_html/*" element={<PageMain lang={lang} type="marmoset" isHtml={isHtml} isLink={isLink} />} /> element={<PageMain lang={lang} type="degu" isHtml={isHtml} isLink={isLink} />}
<Route path="degu/*" element={<PageMain lang={lang} type="degu" isHtml={isHtml} isLink={isLink} />} /> />
<Route path="jm/*" element={<PageMain lang={lang} type="jm" isHtml={isHtml} isLink={isLink} />} /> <Route
<Route path="marmoset/*" element={<PageMain lang={lang} type="marmoset" isHtml={isHtml} isLink={isLink} />} /> path="jm_html/*"
element={<PageMain lang={lang} type="jm" isHtml={isHtml} isLink={isLink} />}
/>
<Route
path="marmoset_html/*"
element={<PageMain lang={lang} type="marmoset" isHtml={isHtml} isLink={isLink} />}
/>
<Route
path="degu/*"
element={<PageMain lang={lang} type="degu" isHtml={isHtml} isLink={isLink} />}
/>
<Route
path="jm/*"
element={<PageMain lang={lang} type="jm" isHtml={isHtml} isLink={isLink} />}
/>
<Route
path="marmoset/*"
element={<PageMain lang={lang} type="marmoset" isHtml={isHtml} isLink={isLink} />}
/>
<Route path="*" element={<PageNotFound lang={lang} />} /> <Route path="*" element={<PageNotFound lang={lang} />} />
</Routes> </Routes>
</div> </div>

View File

@ -1,6 +1,7 @@
import React from "react"; import React from 'react';
import { Link } from "react-router-dom";
import { BrainAtlasType, MultiLang } from "../config"; import { Link } from 'react-router-dom';
import { BrainAtlasType, MultiLang } from '../config';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -8,25 +9,40 @@ interface Props {
isLink: boolean; isLink: boolean;
} }
const Footer: React.FC<Props> = (props: Props) => { const Footer: React.FC<Props> = (props) => {
const { type, isLink } = props; const { type, isLink } = props;
return ( return (
<footer> <footer>
<div className="links clearfix"> <div className="links clearfix">
<span className={`image ${type}`}>&nbsp;</span> <span className={`image ${type}`}>&nbsp;</span>
{!isLink && ( {!isLink && (
<Link className="relatedLink" to={"/" + type + "_html/link.html"}> <Link className="relatedLink" to={'/' + type + '_html/link.html'}>
<span>Related Link</span> <span>Related Link</span>
</Link> </Link>
)} )}
<a className="bsi-ni" href="https://bsi-ni.brain.riken.jp/" target="_blank" rel="noopener noreferrer"> <a
className="bsi-ni"
href="https://bsi-ni.brain.riken.jp/"
target="_blank"
rel="noopener noreferrer"
>
<span>BSI-Neuroinformatics</span> <span>BSI-Neuroinformatics</span>
</a> </a>
<span className="gotoTop"> <span className="gotoTop">
<Link to="/">&raquo; GO TO TOP</Link> <Link to="/">&raquo; GO TO TOP</Link>
</span> </span>
</div> </div>
{type === "marmoset" ? <div className="copyright">Copyright (C) 2018 Laboratory for Symbolic Cognitive Development, RIKEN Center for Biosystems Dynamics Research.</div> : <div className="copyright">Copyright (C) 2017 BSI-NI Project &amp; Laboratory for Symbolic Cognitive Development, RIKEN Brain Science Insititute.</div>} {type === 'marmoset' ? (
<div className="copyright">
Copyright (C) 2018 Laboratory for Symbolic Cognitive Development, RIKEN Center for
Biosystems Dynamics Research.
</div>
) : (
<div className="copyright">
Copyright (C) 2017 BSI-NI Project &amp; Laboratory for Symbolic Cognitive Development,
RIKEN Brain Science Insititute.
</div>
)}
</footer> </footer>
); );
}; };

View File

@ -1,58 +1,59 @@
import React from "react"; import React from 'react';
import { Helmet } from "react-helmet-async";
import { Link, useLocation } from "react-router-dom"; import { Helmet } from 'react-helmet-async';
import Config, { BrainAtlasType, MultiLang } from "../config"; import { Link, useLocation } from 'react-router-dom';
import Config, { BrainAtlasType, MultiLang } from '../config';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
type HeaderType = BrainAtlasType | "marmoset_3d" | "marmoset_std"; type HeaderType = BrainAtlasType | 'marmoset_3d' | 'marmoset_std';
const titles = { const titles = {
degu: "Degu - 3D Brain Atlas", degu: 'Degu - 3D Brain Atlas',
jm: "Japanese Macaque Monkey - the MRI Standard Brain", jm: 'Japanese Macaque Monkey - the MRI Standard Brain',
marmoset: "Marmoset", marmoset: 'Marmoset',
marmoset_3d: "Marmoset - 3D Brain Atlas", marmoset_3d: 'Marmoset - 3D Brain Atlas',
marmoset_std: "Marmoset - the MRI Standard Brain", marmoset_std: 'Marmoset - the MRI Standard Brain',
}; };
const urls = { const urls = {
degu: "/degu/modules/xoonips/listitem.php?index_id=24", degu: '/degu/modules/xoonips/listitem.php?index_id=24',
jm: "/jm/modules/xoonips/listitem.php?index_id=9", jm: '/jm/modules/xoonips/listitem.php?index_id=9',
marmoset: "/marmoset_html/", marmoset: '/marmoset_html/',
marmoset_3d: "/marmoset/modules/xoonips/listitem.php?index_id=66", marmoset_3d: '/marmoset/modules/xoonips/listitem.php?index_id=66',
marmoset_std: "/marmoset/modules/xoonips/listitem.php?index_id=71", marmoset_std: '/marmoset/modules/xoonips/listitem.php?index_id=71',
}; };
const getHeaderType = (type: BrainAtlasType, pathname: string, search: string): HeaderType => { const getHeaderType = (type: BrainAtlasType, pathname: string, search: string): HeaderType => {
if (type === "marmoset") { if (type === 'marmoset') {
const params = new URLSearchParams(search); const params = new URLSearchParams(search);
switch (pathname) { switch (pathname) {
case "/marmoset/modules/xoonips/listitem.php": { case '/marmoset/modules/xoonips/listitem.php': {
const index_id = params.get("index_id") || "3"; const index_id = params.get('index_id') ?? '3';
if (["66", "69"].includes(index_id)) { if (['66', '69'].includes(index_id)) {
return "marmoset_3d"; return 'marmoset_3d';
} }
if (["71", "73"].includes(index_id)) { if (['71', '73'].includes(index_id)) {
return "marmoset_std"; return 'marmoset_std';
} }
break; break;
} }
case "/marmoset/modules/xoonips/detail.php": { case '/marmoset/modules/xoonips/detail.php': {
const item_id = params.get("item_id") || ""; const item_id = params.get('item_id') ?? '';
if (["77", "75", "79", "80"].includes(item_id)) { if (['77', '75', '79', '80'].includes(item_id)) {
return "marmoset_3d"; return 'marmoset_3d';
} }
if (["72"].includes(item_id)) { if (['72'].includes(item_id)) {
return "marmoset_std"; return 'marmoset_std';
} }
const id = params.get("id") || ""; const id = params.get('id') ?? '';
if (["Marmoset02", "Marmoset04", "Marmoset05", "Marmoset06"].includes(id)) { if (['Marmoset02', 'Marmoset04', 'Marmoset05', 'Marmoset06'].includes(id)) {
return "marmoset_3d"; return 'marmoset_3d';
} }
if (["004"].includes(id)) { if (['004'].includes(id)) {
return "marmoset_std"; return 'marmoset_std';
} }
break; break;
} }
@ -61,19 +62,19 @@ const getHeaderType = (type: BrainAtlasType, pathname: string, search: string):
return type; return type;
}; };
const Header: React.FC<Props> = (props: Props) => { const Header: React.FC<Props> = (props) => {
const { lang, type } = props; const { lang, type } = props;
const location = useLocation(); const location = useLocation();
const { pathname, search } = location; const { pathname, search } = location;
const params = new URLSearchParams(search); const params = new URLSearchParams(search);
params.set("ml_lang", lang === "en" ? "ja" : "en"); params.set('ml_lang', lang === 'en' ? 'ja' : 'en');
const langUrl = location.pathname + "?" + params.toString(); const langUrl = `${location.pathname}?${params.toString()}`;
const langLabel = lang === "en" ? "To Japanese" : "To English"; const langLabel = lang === 'en' ? 'To Japanese' : 'To English';
const xtype = getHeaderType(type, pathname, search); const hType = getHeaderType(type, pathname, search);
const title = Config.SITE_TITLE + " " + titles[xtype]; const title = Config.SITE_TITLE + ' ' + titles[hType];
const url = urls[xtype]; const url = urls[hType];
return ( return (
<header className={xtype}> <header className={hType}>
<Helmet> <Helmet>
<title>{title}</title> <title>{title}</title>
</Helmet> </Helmet>

View File

@ -1,11 +1,12 @@
import React from "react"; import React from 'react';
import { Route, Routes } from "react-router-dom";
import { BrainAtlasType, MultiLang } from "../config"; import { Route, Routes } from 'react-router-dom';
import CoverPage from "../custom/CoverPage"; import { BrainAtlasType, MultiLang } from '../config';
import RelatedLink from "../custom/RelatedLink"; import CoverPage from '../custom/CoverPage';
import Database from "../database/Database"; import RelatedLink from '../custom/RelatedLink';
import DatabaseTop from "../database/DatabaseTop"; import Database from '../database/Database';
import XoopsPathRedirect from "./XoopsPathRedirect"; import DatabaseTop from '../database/DatabaseTop';
import XoopsPathRedirect from './XoopsPathRedirect';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -14,7 +15,7 @@ interface Props {
isLink: boolean; isLink: boolean;
} }
const MainContent: React.FC<Props> = (props: Props) => { const MainContent: React.FC<Props> = (props) => {
const { lang, type, isHtml, isLink } = props; const { lang, type, isHtml, isLink } = props;
return ( return (
<div className="mainContent"> <div className="mainContent">

View File

@ -1,26 +1,27 @@
import React from "react"; import React from 'react';
import { Navigate, useLocation } from "react-router-dom";
import { MultiLang } from "../config"; import { Navigate, useLocation } from 'react-router-dom';
import PageNotFound from "./lib/PageNotFound"; import { MultiLang } from '../config';
import PageNotFound from './lib/PageNotFound';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
} }
const XoopsPathRedirect: React.FC<Props> = (props: Props) => { const XoopsPathRedirect: React.FC<Props> = (props) => {
const { lang } = props; const { lang } = props;
const location = useLocation(); const location = useLocation();
const { pathname } = location; const { pathname } = location;
const getRedirectUrl = () => { const getRedirectUrl = () => {
switch (pathname || "") { switch (pathname || '') {
case "/index.php": { case '/index.php': {
return "/"; return '/';
} }
} }
return ""; return '';
}; };
const url = getRedirectUrl(); const url = getRedirectUrl();
if (url === "") { if (url === '') {
return <PageNotFound lang={lang} />; return <PageNotFound lang={lang} />;
} }
return <Navigate to={url} />; return <Navigate to={url} />;

View File

@ -141,7 +141,7 @@ tr.even:hover {
} }
.clearfix::after { .clearfix::after {
content: ""; content: '';
display: block; display: block;
clear: both; clear: both;
} }

View File

@ -1,17 +1,62 @@
img {border: 0;} img {
border: 0;
}
#xoopsHiddenText {visibility: hidden; color: #000000; font-weight: normal; font-style: normal; text-decoration: none;} #xoopsHiddenText {
visibility: hidden;
color: #000000;
font-weight: normal;
font-style: normal;
text-decoration: none;
}
.pagneutral {font-size: 10px; width: 16px; height: 19px;text-align: center; background-image: url(./images/pagneutral.gif);} .pagneutral {
.pagact {font-size: 10px; width: 16px; height: 19px;text-align: center; background-image: url(./images/pagact.gif);} font-size: 10px;
.paginact {font-size: 10px; width: 16px; height: 19px;text-align: center; background-image: url(./images/paginact.gif);} width: 16px;
height: 19px;
text-align: center;
background-image: url(./images/pagneutral.gif);
}
.pagact {
font-size: 10px;
width: 16px;
height: 19px;
text-align: center;
background-image: url(./images/pagact.gif);
}
.paginact {
font-size: 10px;
width: 16px;
height: 19px;
text-align: center;
background-image: url(./images/paginact.gif);
}
#mainmenu a {
text-align: left;
display: block;
margin: 0;
padding: 4px;
}
#mainmenu a.menuTop {
padding-left: 3px;
}
#mainmenu a.menuMain {
padding-left: 3px;
}
#mainmenu a.menuSub {
padding-left: 9px;
}
#mainmenu a {text-align:left; display: block; margin: 0; padding: 4px;} #usermenu a {
#mainmenu a.menuTop {padding-left: 3px;} text-align: left;
#mainmenu a.menuMain {padding-left: 3px;} display: block;
#mainmenu a.menuSub {padding-left: 9px;} margin: 0;
padding: 4px;
#usermenu a {text-align:left; display: block; margin: 0; padding: 4px;} }
#usermenu a.menuTop {} #usermenu a.menuTop {
#usermenu a.highlight {color: #0000ff; background-color: #fcc;} }
#usermenu a.highlight {
color: #0000ff;
background-color: #fcc;
}

View File

@ -1,5 +1,6 @@
import React, { Component } from "react"; import React from 'react';
import { Link } from "react-router-dom";
import { Link } from 'react-router-dom';
interface Props { interface Props {
url: string; url: string;
@ -8,50 +9,40 @@ interface Props {
imageHover?: string; imageHover?: string;
} }
interface State { const LinkImage: React.FC<Props> = (props) => {
image: string; const { url, title, image: imageNormal, imageHover } = props;
} const [image, setImage] = React.useState<string>(imageNormal);
class LinkImage extends Component<Props, State> { const handleMouseOver = () => {
constructor(props: Props) { if (imageHover != null) {
super(props); setImage(imageHover);
this.state = { }
image: props.image,
}; };
this.handleMouseOver = this.handleMouseOver.bind(this);
this.handleMouseOut = this.handleMouseOut.bind(this);
}
handleMouseOver() { const handleMouseOut = () => {
const { imageHover } = this.props; if (imageHover != null) {
if (typeof imageHover !== "undefined") { setImage(imageNormal);
this.setState({ image: imageHover });
}
} }
};
handleMouseOut() {
const { image: imageNormal, imageHover } = this.props;
if (typeof imageHover !== "undefined") {
this.setState({ image: imageNormal });
}
}
render() {
const { url, title } = this.props;
const image = <img style={{ verticalAlign: "middle" }} src={this.state.image} alt={title} title={title} />;
if (url.match(/^(\/|\.)/) === null) { if (url.match(/^(\/|\.)/) === null) {
return ( return (
<a href={url} target="_blank" rel="noopener noreferrer" onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}> <a
href={url}
target="_blank"
rel="noopener noreferrer"
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
>
{image} {image}
</a> </a>
); );
} }
return ( return (
<Link to={url} onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}> <Link to={url} onMouseOver={handleMouseOver} onMouseOut={handleMouseOut}>
{image} <img style={{ verticalAlign: 'middle' }} src={image} alt={title} title={title} />
</Link> </Link>
); );
} };
}
export default LinkImage; export default LinkImage;

View File

@ -1,10 +1,18 @@
import React from "react"; import React from 'react';
import Spinner from "react-spinner-material";
import Spinner from 'react-spinner-material';
const Loading: React.FC = () => { const Loading: React.FC = () => {
return ( return (
<div style={{ display: "flex", justifyContent: "center", alignContent: "center", margin: "100px 0" }}> <div
<Spinner radius={60} color={"#cccccc"} stroke={8} visible={true} /> style={{
display: 'flex',
justifyContent: 'center',
alignContent: 'center',
margin: '100px 0',
}}
>
<Spinner radius={60} color={'#cccccc'} stroke={8} visible={true} />
</div> </div>
); );
}; };

View File

@ -1,15 +1,17 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../config";
import Functions from "../../functions"; import { MultiLang } from '../../config';
import Functions from '../../functions';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
} }
const NoticeSiteHasBeenArchived: React.FC<Props> = (props: Props) => { const NoticeSiteHasBeenArchived: React.FC<Props> = (props) => {
const { lang } = props; const { lang } = props;
const notice = "[en]This site has been archived since FY2019 and is no longer updated.[/en][ja]このサイトは、2019年度よりアーカイブサイトとして運用されています。[/ja]"; const notice =
return <p style={{ color: "red" }}>{Functions.mlang(notice, lang)}</p>; '[en]This site has been archived since FY2019 and is no longer updated.[/en][ja]このサイトは、2019年度よりアーカイブサイトとして運用されています。[/ja]';
return <p style={{ color: 'red' }}>{Functions.mlang(notice, lang)}</p>;
}; };
export default NoticeSiteHasBeenArchived; export default NoticeSiteHasBeenArchived;

View File

@ -1,8 +1,8 @@
import React, { useEffect } from "react"; import React from 'react';
import { Helmet } from "react-helmet-async";
import { useLocation, useNavigate } from "react-router-dom"; import { Helmet } from 'react-helmet-async';
import { MultiLang } from "../../config"; import { MultiLang } from '../../config';
import Functions from "../../functions"; import Functions from '../../functions';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -10,26 +10,7 @@ interface Props {
const PageNotFound: React.FC<Props> = (props) => { const PageNotFound: React.FC<Props> = (props) => {
const { lang } = props; const { lang } = props;
const location = useLocation(); const url = '/';
const navigate = useNavigate();
const url = "/";
useEffect(() => {
let timer: NodeJS.Timeout | null = null;
if (location.pathname !== "/" && process.env.NODE_ENV === 'production') {
if (timer === null) {
timer = setTimeout(() => {
navigate(url);
}, 5000);
}
}
return () => {
if (timer !== null) {
clearTimeout(timer);
timer = null;
}
};
}, [location, navigate]);
return ( return (
<div> <div>
@ -38,7 +19,7 @@ const PageNotFound: React.FC<Props> = (props) => {
</Helmet> </Helmet>
<h1>Page Not Found</h1> <h1>Page Not Found</h1>
<section> <section>
<p>The page you were trying to access doesn't exist.</p> <p>The page you were trying to access doesn&apos;t exist.</p>
<p> <p>
If the page does not automatically reload, please click <a href={url}>here</a> If the page does not automatically reload, please click <a href={url}>here</a>
</p> </p>

View File

@ -1,13 +1,15 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../config";
import Functions from "../../functions"; import { MultiLang } from '../../config';
import imageRank2 from "../assets/images/rank3dbf8e94a6f72.gif"; import Functions from '../../functions';
import imageRank3 from "../assets/images/rank3dbf8e9e7d88d.gif";
import imageRank4 from "../assets/images/rank3dbf8ea81e642.gif"; import imageRank2 from '../assets/images/rank3dbf8e94a6f72.gif';
import imageRank5 from "../assets/images/rank3dbf8eb1a72e7.gif"; import imageRank3 from '../assets/images/rank3dbf8e9e7d88d.gif';
import imageRank6 from "../assets/images/rank3dbf8edf15093.gif"; import imageRank4 from '../assets/images/rank3dbf8ea81e642.gif';
import imageRank7 from "../assets/images/rank3dbf8ee8681cd.gif"; import imageRank5 from '../assets/images/rank3dbf8eb1a72e7.gif';
import imageRank1 from "../assets/images/rank3e632f95e81ca.gif"; import imageRank6 from '../assets/images/rank3dbf8edf15093.gif';
import imageRank7 from '../assets/images/rank3dbf8ee8681cd.gif';
import imageRank1 from '../assets/images/rank3e632f95e81ca.gif';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -16,16 +18,52 @@ interface Props {
} }
const userRanks = [ const userRanks = [
{ title: "[en]Just popping in[/en][ja]新米[/ja]", min: 0, max: 20, special: false, image: imageRank1 }, {
{ title: "[en]Not too shy to talk[/en][ja]半人前[/ja]", min: 21, max: 40, special: false, image: imageRank2 }, title: '[en]Just popping in[/en][ja]新米[/ja]',
{ title: "[en]Quite a regular[/en][ja]常連[/ja]", min: 41, max: 70, special: false, image: imageRank3 }, min: 0,
{ title: "[en]Just can't stay away[/en][ja]一人前[/ja]", min: 71, max: 150, special: false, image: imageRank4 }, max: 20,
{ title: "[en]Home away from home[/en][ja]長老[/ja]", min: 151, max: 10000, special: false, image: imageRank5 }, special: false,
{ title: "[en]Moderator[/en][ja]モデレータ[/ja]", min: 0, max: 0, special: true, image: imageRank6 }, image: imageRank1,
{ title: "[en]Webmaster[/en][ja]管理人[/ja]", min: 0, max: 0, special: true, image: imageRank7 }, },
{
title: '[en]Not too shy to talk[/en][ja]半人前[/ja]',
min: 21,
max: 40,
special: false,
image: imageRank2,
},
{
title: '[en]Quite a regular[/en][ja]常連[/ja]',
min: 41,
max: 70,
special: false,
image: imageRank3,
},
{
title: "[en]Just can't stay away[/en][ja]一人前[/ja]",
min: 71,
max: 150,
special: false,
image: imageRank4,
},
{
title: '[en]Home away from home[/en][ja]長老[/ja]',
min: 151,
max: 10000,
special: false,
image: imageRank5,
},
{
title: '[en]Moderator[/en][ja]モデレータ[/ja]',
min: 0,
max: 0,
special: true,
image: imageRank6,
},
{ title: '[en]Webmaster[/en][ja]管理人[/ja]', min: 0, max: 0, special: true, image: imageRank7 },
]; ];
const UserRankStarImage: React.FC<Props> = (props: Props) => { const UserRankStarImage: React.FC<Props> = (props) => {
const { lang, rank, posts } = props; const { lang, rank, posts } = props;
const findRank = (posts: number) => { const findRank = (posts: number) => {
const rank = userRanks.find((userRank) => { const rank = userRanks.find((userRank) => {
@ -34,7 +72,7 @@ const UserRankStarImage: React.FC<Props> = (props: Props) => {
} }
return false; return false;
}); });
return typeof rank !== "undefined" ? rank : userRanks[0]; return typeof rank !== 'undefined' ? rank : userRanks[0];
}; };
const userRank = rank > 0 && rank <= 7 ? userRanks[rank - 1] : findRank(posts); const userRank = rank > 0 && rank <= 7 ? userRanks[rank - 1] : findRank(posts);
const title = Functions.mlang(userRank.title, lang); const title = Functions.mlang(userRank.title, lang);

View File

@ -1,8 +1,15 @@
import ReactHtmlParser, { convertNodeToElement, DomElement, DomNode, Transform } from "@orrisroot/react-html-parser"; import React from 'react';
import React from "react";
import { HashLink } from "react-router-hash-link"; import ReactHtmlParser, {
import { MultiLang } from "../../config"; convertNodeToElement,
import Functions from "../../functions"; DomElement,
DomNode,
Transform,
} from '@orrisroot/react-html-parser';
import { ElementType } from 'htmlparser2';
import { HashLink } from 'react-router-hash-link';
import { MultiLang } from '../../config';
import Functions from '../../functions';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -16,8 +23,8 @@ interface Props {
const preConvertXCode = (text: string, doxcode: boolean): string => { const preConvertXCode = (text: string, doxcode: boolean): string => {
if (doxcode) { if (doxcode) {
return text.replace(/\[code\](.*)\[\/code\]/gs, (m0, m1) => { return text.replace(/\[code\](.*)\[\/code\]/gs, (_: string, m1: string) => {
return "[code]" + Functions.base64Encode(m1) + "[/code]"; return '[code]' + Functions.base64Encode(m1) + '[/code]';
}); });
} }
return text; return text;
@ -25,26 +32,42 @@ const preConvertXCode = (text: string, doxcode: boolean): string => {
const postConvertXCode = (text: string, doxcode: boolean, doimage: boolean): string => { const postConvertXCode = (text: string, doxcode: boolean, doimage: boolean): string => {
if (doxcode) { if (doxcode) {
return text.replace(/\[code\](.*)\[\/code\]/gs, (m0, m1) => { return text.replace(/\[code\](.*)\[\/code\]/gs, (_: string, m1: string) => {
const text = convertXCode(Functions.htmlspecialchars(Functions.base64Decode(m1)), doimage); const text = convertXCode(Functions.htmlspecialchars(Functions.base64Decode(m1)), doimage);
return '<div class="xoopsCode"><pre><code>' + text + "</code></pre></div>"; return '<div class="xoopsCode"><pre><code>' + text + '</code></pre></div>';
}); });
} }
return text; return text;
}; };
const convertClickable = (text: string) => { const convertClickable = (text: string) => {
text = text.replace(/(^|[^\]_a-zA-Z0-9-="'/]+)((?:https?|ftp)(?::\/\/[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+[a-zA-Z0-9=]))/g, (...matches) => { text = text.replace(
return matches[1] + '<a href="' + matches[2] + '" target="_blank" rel="external noopener noreferrer">' + matches[2] + "</a>"; /(^|[^\]_a-zA-Z0-9-="'/]+)((?:https?|ftp)(?::\/\/[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+[a-zA-Z0-9=]))/g,
}); (...matches) => {
text = text.replace(/(^|[^\]_a-zA-Z0-9-="'/:.]+)([a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+)/g, (...matches) => { return (
return matches[1] + '<a href="mailto:' + matches[2] + '">' + matches[2] + "</a>"; matches[1] +
}); '<a href="' +
matches[2] +
'" target="_blank" rel="external noopener noreferrer">' +
matches[2] +
'</a>'
);
},
);
text = text.replace(
/(^|[^\]_a-zA-Z0-9-="'/:.]+)([a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+)/g,
(...matches) => {
return matches[1] + '<a href="mailto:' + matches[2] + '">' + matches[2] + '</a>';
},
);
return text; return text;
}; };
const convertXCode = (text: string, doimage: boolean): string => { const convertXCode = (text: string, doimage: boolean): string => {
// TODO: implement // TODO: implement
if (doimage) {
return text;
}
return text; return text;
}; };
@ -54,17 +77,17 @@ const convertSmiley = (text: string) => {
}; };
const convertBr = (text: string): string => { const convertBr = (text: string): string => {
return text.replace(/(\r?\n|\r)/g, "<br />"); return text.replace(/(\r?\n|\r)/g, '<br />');
}; };
const cssConvert = (text: string): object => { const cssConvert = (text: string): Record<string, string> => {
const ret: any = {}; const ret: Record<string, string> = {};
text.split(";").forEach((line) => { text.split(';').forEach((line) => {
const line_ = line.trim(); const line_ = line.trim();
if (line.length === 0) { if (line.length === 0) {
return; return;
} }
const kv = line_.split(":"); const kv = line_.split(':');
const key = Functions.camelCase(kv[0].trim()); const key = Functions.camelCase(kv[0].trim());
const value = kv[1].trim(); const value = kv[1].trim();
ret[key] = value; ret[key] = value;
@ -72,19 +95,24 @@ const cssConvert = (text: string): object => {
return ret; return ret;
}; };
const xoopsTransform: Transform = (node: DomNode, index: number | string, transform?: Transform): React.ReactNode => { const xoopsTransform: Transform = (
if (node.type === "tag") { node: DomNode,
index: number | string,
transform?: Transform,
): React.ReactNode => {
if (node.type === ElementType.Tag) {
const node_ = node as DomElement; const node_ = node as DomElement;
if (node_.name === "a") { if (node_.name === 'a') {
const url = node_.attribs?.["href"] || "/"; const url = node_.attribs?.href ?? '/';
const download = (node_.attribs && node_.attribs["download"]) || ""; const download = node_.attribs?.download ?? '';
const rel = (node_.attribs && node_.attribs["rel"]) || ""; const rel = node_.attribs?.rel ?? '';
const klass = (node_.attribs && node_.attribs["class"]) || ""; const className = node_.attribs?.class ?? '';
const isFile = download !== "" || /\.(zip|pdf|png|gif|jpg)$/.test(url); const isFile = download !== '' || /\.(zip|pdf|png|gif|jpg)$/.test(url);
const isExternal = /external/.test(rel) || /external/.test(klass) || /^(mailto|https?:?\/\/)/.test(url); const isExternal =
/external/.test(rel) || /external/.test(className) || /^(mailto|https?:?\/\/)/.test(url);
if (!isFile && !isExternal) { if (!isFile && !isExternal) {
const style = node_.attribs?.["style"] || ""; const style = node_.attribs?.style || '';
const title = node_.attribs?.["title"]; const title = node_.attribs?.title;
return ( return (
<HashLink key={index} to={url} style={cssConvert(style)} title={title}> <HashLink key={index} to={url} style={cssConvert(style)} title={title}>
{node_.children.map((value: DomNode, index: number) => { {node_.children.map((value: DomNode, index: number) => {
@ -94,15 +122,15 @@ const xoopsTransform: Transform = (node: DomNode, index: number | string, transf
); );
} }
} }
if (node_.name === "img") { if (node_.name === 'img') {
const src = (node_.attribs && node_.attribs["src"]) || ""; const src = node_.attribs?.src ?? '';
node_.attribs["src"] = src.replace("`XOOPS_URL`", process.env.PUBLIC_URL); node_.attribs.src = src.replace('`XOOPS_URL`', '/');
return convertNodeToElement(node_, index, transform); return convertNodeToElement(node_, index, transform);
} }
} }
}; };
const XoopsCode: React.FC<Props> = (props: Props) => { const XoopsCode: React.FC<Props> = (props) => {
const { lang } = props; const { lang } = props;
let text = props.text; let text = props.text;
const dohtml = !!props.dohtml; const dohtml = !!props.dohtml;

View File

@ -1,12 +1,12 @@
const SITE_TITLE = "BSI-NI Brain Atlas"; const SITE_TITLE = 'BSI-NI Brain Atlas';
const SITE_SLOGAN = "Welcome to BRAIN ATLAS"; const SITE_SLOGAN = 'Welcome to BRAIN ATLAS';
const GOOGLE_ANALYTICS_TRACKING_ID = ""; const GOOGLE_ANALYTICS_TRACKING_ID = '';
const XOONIPS_ITEMTYPES = ["files", "url", "paper", "book"]; const XOONIPS_ITEMTYPES = ['files', 'url', 'paper', 'book'];
export type MultiLang = "en" | "ja"; export type MultiLang = 'en' | 'ja';
export type BrainAtlasType = "degu" | "jm" | "marmoset"; export type BrainAtlasType = 'degu' | 'jm' | 'marmoset';
export const BrainAtlasTypes: ReadonlyArray<BrainAtlasType> = ["degu", "jm", "marmoset"]; export const BrainAtlasTypes: readonly BrainAtlasType[] = ['degu', 'jm', 'marmoset'];
const Config = { const Config = {
SITE_TITLE, SITE_TITLE,

View File

@ -1,21 +1,25 @@
import React from "react"; import React from 'react';
import { Link } from "react-router-dom";
import PageNotFound from "../common/lib/PageNotFound"; import { Link } from 'react-router-dom';
import { BrainAtlasType, MultiLang } from "../config"; import PageNotFound from '../common/lib/PageNotFound';
import styles from "./CoverPage.module.css"; import { BrainAtlasType, MultiLang } from '../config';
import styles from './CoverPage.module.css';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
const CoverPage: React.FC<Props> = (props: Props) => { const CoverPage: React.FC<Props> = (props) => {
const { lang, type } = props; const { lang, type } = props;
const links = [ const links = [
{ title: "Marmoset-3D Brain Atlas", url: "/marmoset/modules/xoonips/listitem.php?index_id=66" }, { title: 'Marmoset-3D Brain Atlas', url: '/marmoset/modules/xoonips/listitem.php?index_id=66' },
{ title: "Marmoset-the MRI Standard Brain", url: "/marmoset/modules/xoonips/listitem.php?index_id=71" }, {
title: 'Marmoset-the MRI Standard Brain',
url: '/marmoset/modules/xoonips/listitem.php?index_id=71',
},
]; ];
if (type !== "marmoset") { if (type !== 'marmoset') {
return <PageNotFound lang={lang} />; return <PageNotFound lang={lang} />;
} }
return ( return (

View File

@ -1,22 +1,29 @@
import React from "react"; import React from 'react';
import { BrainAtlasType, MultiLang } from "../config";
import styles from "./RelatedLink.module.css"; import { BrainAtlasType, MultiLang } from '../config';
import styles from './RelatedLink.module.css';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
const RelatedLink: React.FC<Props> = (props: Props) => { const RelatedLink: React.FC<Props> = (props) => {
const { type } = props; const { type } = props;
const links = { const links = {
degu: [{ title: "RIKEN BSI", url: "http://www.brain.riken.jp/" }], degu: [{ title: 'RIKEN BSI', url: 'http://www.brain.riken.jp/' }],
jm: [{ title: "RIKEN BSI", url: "http://www.brain.riken.jp/" }], jm: [{ title: 'RIKEN BSI', url: 'http://www.brain.riken.jp/' }],
marmoset: [ marmoset: [
{ title: "RIKEN BSI", url: "http://www.brain.riken.jp/" }, { title: 'RIKEN BSI', url: 'http://www.brain.riken.jp/' },
{ title: "Keio-RIKEN Research centre for Human Congnition", url: "http://human-cognition.keio.ac.jp/english/" }, {
{ title: "FIRST project", url: "http://www.brain.riken.jp/first-okano/en/index.html" }, title: 'Keio-RIKEN Research centre for Human Cognition',
{ title: "Press release", url: "http://www.brain.riken.jp/first-okano/en/achievements/2010/papers.html" }, url: 'http://human-cognition.keio.ac.jp/english/',
},
{ title: 'FIRST project', url: 'http://www.brain.riken.jp/first-okano/en/index.html' },
{
title: 'Press release',
url: 'http://www.brain.riken.jp/first-okano/en/achievements/2010/papers.html',
},
], ],
}; };
return ( return (

View File

@ -1,14 +1,15 @@
import React from "react"; import React from 'react';
import { Link } from "react-router-dom";
import NoticeSiteHasBeenArchived from "../common/lib/NoticeSiteHasBeenArchived"; import { Link } from 'react-router-dom';
import { MultiLang } from "../config"; import NoticeSiteHasBeenArchived from '../common/lib/NoticeSiteHasBeenArchived';
import styles from "./SiteIndex.module.css"; import { MultiLang } from '../config';
import styles from './SiteIndex.module.css';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
} }
const SiteIndex: React.FC<Props> = (props: Props) => { const SiteIndex: React.FC<Props> = (props) => {
const { lang } = props; const { lang } = props;
return ( return (
<div className={styles.siteIndex}> <div className={styles.siteIndex}>
@ -29,7 +30,10 @@ const SiteIndex: React.FC<Props> = (props: Props) => {
</Link> </Link>
</li> </li>
<li className={styles.jm}> <li className={styles.jm}>
<Link to="/jm/modules/xoonips/listitem.php?index_id=9" title="Japanese Macaque Monkey"> <Link
to="/jm/modules/xoonips/listitem.php?index_id=9"
title="Japanese Macaque Monkey"
>
<span>Japanese Macaque Monkey</span> <span>Japanese Macaque Monkey</span>
</Link> </Link>
</li> </li>

View File

@ -1,88 +1,102 @@
import React from "react"; import React from 'react';
import { Helmet } from "react-helmet-async";
import { Route, Routes, useLocation } from "react-router-dom"; import { Helmet } from 'react-helmet-async';
import PageNotFound from "../common/lib/PageNotFound"; import { Route, Routes, useLocation } from 'react-router-dom';
import { BrainAtlasType, MultiLang } from "../config"; import PageNotFound from '../common/lib/PageNotFound';
import Functions from "../functions"; import { BrainAtlasType, MultiLang } from '../config';
import styles from "./Database.module.css"; import Functions from '../functions';
import DatabaseAdvancedSearch from "./DatabaseAdvancedSearch"; import styles from './Database.module.css';
import DatabaseDetailItem from "./DatabaseDetailItem"; import DatabaseAdvancedSearch from './DatabaseAdvancedSearch';
import DatabaseSearchByAdvancedKeyword from "./DatabaseSearchByAdvancedKeyword"; import DatabaseDetailItem from './DatabaseDetailItem';
import DatabaseSearchByIndexId from "./DatabaseSearchByIndexId"; import DatabaseSearchByAdvancedKeyword from './DatabaseSearchByAdvancedKeyword';
import DatabaseSearchByItemType from "./DatabaseSearchByItemType"; import DatabaseSearchByIndexId from './DatabaseSearchByIndexId';
import DatabaseSearchByKeyword from "./DatabaseSearchByKeyword"; import DatabaseSearchByItemType from './DatabaseSearchByItemType';
import DatabaseTop from "./DatabaseTop"; import DatabaseSearchByKeyword from './DatabaseSearchByKeyword';
import { INDEX_ID_PUBLIC } from "./lib/IndexUtil"; import DatabaseTop from './DatabaseTop';
import { INDEX_ID_PUBLIC } from './lib/IndexUtil';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
const ItemDetail: React.FC<Props> = (props: Props) => { const ItemDetail: React.FC<Props> = (props) => {
const { lang, type } = props; const { lang, type } = props;
const location = useLocation(); const location = useLocation();
const params = new URLSearchParams(location.search); const params = new URLSearchParams(location.search);
const itemId_ = params.get("item_id") || ""; const itemId_ = params.get('item_id') ?? '';
const itemId = /^\d+$/.test(itemId_) ? parseInt(itemId_, 10) : 0; const itemId = /^\d+$/.test(itemId_) ? parseInt(itemId_, 10) : 0;
const doi = params.get("id") || ""; const doi = params.get('id') ?? '';
return <DatabaseDetailItem lang={lang} id={itemId} doi={doi} type={type} />; return <DatabaseDetailItem lang={lang} id={itemId} doi={doi} type={type} />;
}; };
const ItemList: React.FC<Props> = (props: Props) => { const ItemList: React.FC<Props> = (props) => {
const { lang, type } = props; const { lang, type } = props;
const location = useLocation(); const location = useLocation();
const params = new URLSearchParams(location.search); const params = new URLSearchParams(location.search);
const id = params.get("index_id") || ""; const id = params.get('index_id') ?? '';
const indexId = /^\d+$/.test(id) ? parseInt(id, 10) : INDEX_ID_PUBLIC; const indexId = /^\d+$/.test(id) ? parseInt(id, 10) : INDEX_ID_PUBLIC;
return <DatabaseSearchByIndexId lang={lang} type={type} indexId={indexId} />; return <DatabaseSearchByIndexId lang={lang} type={type} indexId={indexId} />;
}; };
const ItemSelect: React.FC<Props> = (props: Props) => { const ItemSelect: React.FC<Props> = (props) => {
const { lang, type } = props; const { lang, type } = props;
const location = useLocation(); const location = useLocation();
const params = new URLSearchParams(location.search); const params = new URLSearchParams(location.search);
const op = params.get("op") || ""; const op = params.get('op') ?? '';
switch (op) { switch (op) {
case "itemtypesearch": { case 'itemtypesearch': {
const searchItemtype = params.get("search_itemtype") || ""; const searchItemtype = params.get('search_itemtype') ?? '';
const match = searchItemtype.match(/^xnp([a-z]+)$/); const match = searchItemtype.match(/^xnp([a-z]+)$/);
const itemType = match !== null ? match[1] : ""; const itemType = match !== null ? match[1] : '';
return <DatabaseSearchByItemType lang={lang} itemType={itemType} subItemType="" type={type} />; return (
<DatabaseSearchByItemType lang={lang} itemType={itemType} subItemType="" type={type} />
);
} }
case "itemsubtypesearch": { case 'itemsubtypesearch': {
const searchItemtype = params.get("search_itemtype") || ""; const searchItemtype = params.get('search_itemtype') ?? '';
const match = searchItemtype.match(/^xnp([a-z]+)$/); const match = searchItemtype.match(/^xnp([a-z]+)$/);
const itemType = match !== null ? match[1] : ""; const itemType = match !== null ? match[1] : '';
const subItemtype = params.get("search_subitemtype") || ""; const subItemtype = params.get('search_subitemtype') ?? '';
return <DatabaseSearchByItemType lang={lang} itemType={itemType} subItemType={subItemtype} type={type} />; return (
<DatabaseSearchByItemType
lang={lang}
itemType={itemType}
subItemType={subItemtype}
type={type}
/>
);
} }
case "quicksearch": { case 'quicksearch': {
return <DatabaseSearchByKeyword lang={lang} type={type} />; return <DatabaseSearchByKeyword lang={lang} type={type} />;
} }
case "advanced": { case 'advanced': {
return <DatabaseSearchByAdvancedKeyword lang={lang} type={type} />; return <DatabaseSearchByAdvancedKeyword lang={lang} type={type} />;
} }
} }
return <PageNotFound lang={lang} />; return <PageNotFound lang={lang} />;
}; };
const Database: React.FC<Props> = (props: Props) => { const Database: React.FC<Props> = (props) => {
const { lang, type } = props; const { lang, type } = props;
return ( return (
<div className={styles.database}> <div className={styles.database}>
<Helmet> <Helmet>
<title> <title>
{Functions.mlang("[en]Database[/en][ja]データベース[/ja]", lang)} - {Functions.siteTitle(lang)} {Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} -{' '}
{Functions.siteTitle(lang)}
</title> </title>
</Helmet> </Helmet>
<Routes> <Routes>
<Route index element={<DatabaseTop lang={lang} type={type} />} /> <Route index element={<DatabaseTop lang={lang} type={type} />} />
<Route path="index.php" element={<DatabaseTop lang={lang} type={type} />} /> <Route path="index" element={<DatabaseTop lang={lang} type={type} />} />
<Route path="detail.php" element={<ItemDetail lang={lang} type={type} />} /> <Route path="detail.php" element={<ItemDetail lang={lang} type={type} />} />
<Route path="listitem.php" element={<ItemList lang={lang} type={type} />} /> <Route path="listitem.php" element={<ItemList lang={lang} type={type} />} />
<Route path="itemselect.php" element={<ItemSelect lang={lang} type={type} />} /> <Route path="itemselect.php" element={<ItemSelect lang={lang} type={type} />} />
<Route path="advanced_search.php" element={<DatabaseAdvancedSearch lang={lang} type={type} />} /> <Route
path="advanced_search.php"
element={<DatabaseAdvancedSearch lang={lang} type={type} />}
/>
<Route path="*" element={<PageNotFound lang={lang} />} /> <Route path="*" element={<PageNotFound lang={lang} />} />
</Routes> </Routes>
</div> </div>

View File

@ -1,63 +1,47 @@
import React from "react"; import React from 'react';
import { useNavigate } from "react-router-dom";
import Config, { BrainAtlasType, MultiLang } from "../config";
import Functions from "../functions";
import ItemType from "./item-type";
import AdvancedSearchQuery from "./lib/AdvancedSearchQuery";
import ItemUtil from "./lib/ItemUtil";
interface PropsFC { import { useNavigate } from 'react-router-dom';
import Config, { BrainAtlasType, MultiLang } from '../config';
import Functions from '../functions';
import ItemType from './item-type';
import AdvancedSearchQuery from './lib/AdvancedSearchQuery';
import ItemUtil from './lib/ItemUtil';
interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
interface Props extends PropsFC { const DatabaseAdvancedSearch: React.FC<Props> = (props) => {
navigate: any; const { lang, type } = props;
} const query = new AdvancedSearchQuery();
const navigate = useNavigate();
class DatabaseAdvancedSearch extends React.Component<Props> { const handleClickSearchButton = () => {
private query: AdvancedSearchQuery = new AdvancedSearchQuery(); if (!query.empty()) {
const url = ItemUtil.getSearchByAdvancedKeywordsUrl(type, query);
constructor(props: Props) {
super(props);
this.handleClickSearchButton = this.handleClickSearchButton.bind(this);
}
handleClickSearchButton() {
const { type, navigate } = this.props;
if (!this.query.empty()) {
const url = ItemUtil.getSearchByAdvancedKeywordsUrl(type, this.query);
navigate(url); navigate(url);
} }
} };
render() {
const { lang } = this.props;
return ( return (
<div className="advancedSearch"> <div className="advancedSearch">
<h3>{Functions.mlang("[en]Search Items[/en][ja]アイテム検索[/ja]", lang)}</h3> <h3>{Functions.mlang('[en]Search Items[/en][ja]アイテム検索[/ja]', lang)}</h3>
<div className="search"> <div className="search">
<button className="formButton" onClick={this.handleClickSearchButton}> <button className="formButton" onClick={handleClickSearchButton}>
Search Search
</button> </button>
</div> </div>
{Config.XOONIPS_ITEMTYPES.map((type) => { {Config.XOONIPS_ITEMTYPES.map((type) => {
return <ItemType.AdvancedSearch key={type} type={"xnp" + type} lang={lang} query={this.query} />; return <ItemType.AdvancedSearch key={type} type={`xnp${type}`} lang={lang} query={query} />;
})} })}
<div className="search"> <div className="search">
<button className="formButton" onClick={this.handleClickSearchButton}> <button className="formButton" onClick={handleClickSearchButton}>
Search Search
</button> </button>
</div> </div>
</div> </div>
); );
}
}
const DatabaseAdvancedSearchFC: React.FC<PropsFC> = (props: PropsFC) => {
const { lang, type } = props;
return <DatabaseAdvancedSearch lang={lang} type={type} navigate={useNavigate()} />;
}; };
export default DatabaseAdvancedSearchFC; export default DatabaseAdvancedSearch;

View File

@ -1,11 +1,12 @@
import React from "react"; import React from 'react';
import { Helmet } from "react-helmet-async";
import Loading from "../common/lib/Loading"; import { Helmet } from 'react-helmet-async';
import PageNotFound from "../common/lib/PageNotFound"; import Loading from '../common/lib/Loading';
import { BrainAtlasType, MultiLang } from "../config"; import PageNotFound from '../common/lib/PageNotFound';
import Functions from "../functions"; import { BrainAtlasType, MultiLang } from '../config';
import ItemType from "./item-type"; import Functions from '../functions';
import ItemUtil, { Item } from "./lib/ItemUtil"; import ItemType from './item-type';
import ItemUtil, { Item } from './lib/ItemUtil';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -14,65 +15,49 @@ interface Props {
doi: string; doi: string;
} }
interface State { const DatabaseDetailItem: React.FC<Props> = (props) => {
loading: boolean; const { lang, type, id, doi } = props;
item: Item | null;
}
class DatabaseDetailItem extends React.Component<Props, State> { const [loading, setLoading] = React.useState<boolean>(true);
constructor(props: Props) { const [item, setItem] = React.useState<Item | null>(null);
super(props);
this.state = {
loading: true,
item: null,
};
}
componentDidMount() { React.useEffect(() => {
this.updateItem(); if (doi !== '') {
}
componentDidUpdate(prevProps: Props, prevState: State) {
const { id, doi } = this.props;
if (id !== prevProps.id || doi !== prevProps.doi) {
this.updateItem();
}
}
updateItem() {
const { id, doi, type } = this.props;
if (doi !== "") {
ItemUtil.getByDoi(type, doi, (item) => { ItemUtil.getByDoi(type, doi, (item) => {
this.setState({ loading: false, item }); setItem(item);
setLoading(false);
}); });
} else if (id !== 0) { } else if (id !== 0) {
ItemUtil.get(type, id, (item) => { ItemUtil.get(type, id, (item) => {
this.setState({ loading: false, item }); setItem(item);
setLoading(false);
}); });
} else {
setLoading(true);
} }
} }, [type, id, doi]);
render() { if (loading) {
const { lang, type } = this.props;
if (this.state.loading) {
return <Loading />; return <Loading />;
} }
if (this.state.item === null) { if (item === null) {
return <PageNotFound lang={lang} />; return <PageNotFound lang={lang} />;
} }
return ( return (
<> <>
<Helmet> <Helmet>
<title> <title>
{Functions.mlang(this.state.item.title, lang)} - {Functions.mlang("[en]Database[/en][ja]データベース[/ja]", lang)} - {Functions.siteTitle(lang)} {Functions.mlang(item.title, lang)} -{' '}
{Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} -{' '}
{Functions.siteTitle(lang)}
</title> </title>
</Helmet> </Helmet>
<h3>{Functions.mlang("[en]Detail[/en][ja]詳細[/ja]", lang)}</h3> <h3>{Functions.mlang('[en]Detail[/en][ja]詳細[/ja]', lang)}</h3>
<br /> <br />
<ItemType.Detail lang={lang} item={this.state.item} type={type} /> <ItemType.Detail lang={lang} item={item} type={type} />
</> </>
); );
} };
}
export default DatabaseDetailItem; export default DatabaseDetailItem;

View File

@ -1,67 +1,32 @@
import React from "react"; import React from 'react';
import { useLocation } from "react-router-dom";
import { BrainAtlasType, MultiLang } from "../config";
import AdvancedSearchQuery from "./lib/AdvancedSearchQuery";
import DatabaseListItem from "./lib/DatabaseListItem";
import ItemUtil, { SearchCallbackFunc, SortCondition } from "./lib/ItemUtil";
interface PropsFC { import { useLocation } from 'react-router-dom';
import { BrainAtlasType, MultiLang } from '../config';
import DatabaseListItem from './lib/DatabaseListItem';
import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil';
interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
interface Props extends PropsFC { const DatabaseSearchByAdvancedKeyword: React.FC<Props> = (props) => {
location: any; const { lang, type } = props;
} const location = useLocation();
const query = ItemUtil.getAdvancedSearchQueryByQuery(location.search);
interface State { const searchFunc = (condition: SortCondition, func: SearchCallbackFunc) => {
search: string; ItemUtil.getListByAdvancedSearchQuery(type, query, condition, func);
query: AdvancedSearchQuery; };
}
class DatabaseSearchByAdvancedKeyword extends React.Component<Props, State> { const baseUrl = ItemUtil.getSearchByAdvancedKeywordsUrl(type, query);
constructor(props: Props) {
super(props);
const search = props.location.search;
const query = ItemUtil.getAdvancedSearchQueryByQuery(search);
this.state = { search, query };
this.searchFunc = this.searchFunc.bind(this);
}
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
const search = nextProps.location.search;
if (prevState.search !== search) {
const query = ItemUtil.getAdvancedSearchQueryByQuery(search);
return { search, query };
}
return null;
}
getUrl() {
const { type } = this.props;
return ItemUtil.getSearchByAdvancedKeywordsUrl(type, this.state.query);
}
searchFunc(condition: SortCondition, func: SearchCallbackFunc) {
const { type } = this.props;
ItemUtil.getListByAdvancedSearchQuery(type, this.state.query, condition, func);
}
render() {
const { lang, type } = this.props;
const baseUrl = this.getUrl();
return ( return (
<div className="list"> <div className="list">
<h3>Listing item</h3> <h3>Listing item</h3>
<DatabaseListItem lang={lang} url={baseUrl} search={this.searchFunc} type={type} /> <DatabaseListItem lang={lang} url={baseUrl} search={searchFunc} type={type} />
</div> </div>
); );
}
}
const DatabaseSearchByAdvancedKeywordFC: React.FC<PropsFC> = (props: PropsFC) => {
const { lang, type } = props;
return <DatabaseSearchByAdvancedKeyword lang={lang} type={type} location={useLocation()} />;
}; };
export default DatabaseSearchByAdvancedKeywordFC; export default DatabaseSearchByAdvancedKeyword;

View File

@ -1,80 +1,92 @@
import React, { Fragment } from "react"; import React from 'react';
import { Helmet } from "react-helmet-async";
import { Link } from "react-router-dom";
import PageNotFound from "../common/lib/PageNotFound";
import { BrainAtlasType, MultiLang } from "../config";
import Functions from "../functions";
import DatabaseListIndex from "./lib/DatabaseListIndex";
import DatabaseListItem from "./lib/DatabaseListItem";
import IndexUtil, { Index } from "./lib/IndexUtil";
import ItemUtil, { SearchCallbackFunc, SortCondition } from "./lib/ItemUtil";
export interface Props { import { Helmet } from 'react-helmet-async';
import { Link } from 'react-router-dom';
import Loading from '../common/lib/Loading';
import PageNotFound from '../common/lib/PageNotFound';
import { BrainAtlasType, MultiLang } from '../config';
import Functions from '../functions';
import DatabaseListIndex from './lib/DatabaseListIndex';
import DatabaseListItem from './lib/DatabaseListItem';
import IndexUtil, { Index } from './lib/IndexUtil';
import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil';
interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
indexId: number; indexId: number;
} }
class DatabaseSearchByIndexId extends React.Component<Props> { const DatabaseSearchByIndexId: React.FC<Props> = (props) => {
constructor(props: Props) { const { lang, type, indexId } = props;
super(props);
this.searchFunc = this.searchFunc.bind(this);
}
getUrl() { const [notFound, setNotFound] = React.useState<boolean>(false);
const { type, indexId } = this.props; const [index, setIndex] = React.useState<Index | null>(null);
if (indexId === 0) { const [parents, setParents] = React.useState<{ title: string; node: React.ReactNode }>({
return "/"; title: '',
} node: null,
return IndexUtil.getUrl(type, indexId); });
}
searchFunc(condition: SortCondition, func: SearchCallbackFunc) { const searchFunc = (condition: SortCondition, func: SearchCallbackFunc) => {
const { type, indexId } = this.props;
if (indexId === 0) { if (indexId === 0) {
const res = { total: 0, data: [] }; const res = { total: 0, data: [] };
func(res); func(res);
} else { } else {
ItemUtil.getListByIndexId(type, indexId, condition, func); ItemUtil.getListByIndexId(type, indexId, condition, func);
} }
} };
render() { React.useEffect(() => {
const { lang, type, indexId } = this.props; IndexUtil.get(type, indexId, (index) => {
const index = IndexUtil.get(type, indexId); setIndex(index);
if (index === null) { if (index == null) {
return <PageNotFound lang={lang} />; setNotFound(true);
} } else {
const baseUrl = this.getUrl(); IndexUtil.getParents(type, indexId, (pIndexes) => {
const pIndexes = IndexUtil.getParents(type, indexId); const parents = pIndexes.map((index: Index) => {
const parents = pIndexes.map((value: Index) => { const url: string = IndexUtil.getUrl(type, index.id);
const url: string = IndexUtil.getUrl(type, value.id); const title = Functions.mlang(index.title, lang);
const title = Functions.mlang(value.title, lang);
return ( return (
<Fragment key={value.id}> <React.Fragment key={index.id}>
/ <Link to={url}>{title}</Link>{" "} / <Link to={url}>{title}</Link>{' '}
</Fragment> </React.Fragment>
); );
}); });
const title = pIndexes const title = pIndexes
.map((value) => { .map((index) => {
return "/" + Functions.mlang(value.title, lang); return '/' + Functions.mlang(index.title, lang);
}) })
.join(""); .join('');
setParents({ title: title, node: parents });
});
}
});
}, [indexId, lang, type]);
if (notFound) {
return <PageNotFound lang={lang} />;
}
if (index == null) {
return <Loading />;
}
const baseUrl = indexId === 0 ? '/' : IndexUtil.getUrl(type, indexId);
return ( return (
<div className="list"> <div className="list">
<Helmet> <Helmet>
<title> <title>
{Functions.mlang(title, lang)} - {Functions.mlang("[en]Database[/en][ja]データベース[/ja]", lang)} - {Functions.siteTitle(lang)} {Functions.mlang(parents.title, lang)} -{' '}
{Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} -{' '}
{Functions.siteTitle(lang)}
</title> </title>
</Helmet> </Helmet>
<h3>{Functions.mlang("[en]Listing item[/en][ja]アイテム一覧[/ja]", lang)}</h3> <h3>{Functions.mlang('[en]Listing item[/en][ja]アイテム一覧[/ja]', lang)}</h3>
<div>{parents}</div> <div>{parents.node}</div>
<DatabaseListIndex lang={lang} index={index} type={type} /> <DatabaseListIndex lang={lang} index={index} type={type} />
<DatabaseListItem lang={lang} url={baseUrl} search={this.searchFunc} type={type} /> <DatabaseListItem lang={lang} url={baseUrl} search={searchFunc} type={type} />
</div> </div>
); );
} };
}
export default DatabaseSearchByIndexId; export default DatabaseSearchByIndexId;

View File

@ -1,8 +1,9 @@
import React from "react"; import React from 'react';
import { BrainAtlasType, MultiLang } from "../config";
import Functions from "../functions"; import { BrainAtlasType, MultiLang } from '../config';
import DatabaseListItem from "./lib/DatabaseListItem"; import Functions from '../functions';
import ItemUtil, { SearchCallbackFunc, SortCondition } from "./lib/ItemUtil"; import DatabaseListItem from './lib/DatabaseListItem';
import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -11,38 +12,26 @@ interface Props {
type: BrainAtlasType; type: BrainAtlasType;
} }
class DatabaseSearchByItemType extends React.Component<Props> { const DatabaseSearchByItemType: React.FC<Props> = (props) => {
constructor(props: Props) { const { lang, itemType, subItemType, type } = props;
super(props);
this.searchFunc = this.searchFunc.bind(this);
}
searchFunc(condition: SortCondition, func: SearchCallbackFunc) { const searchFunc = (condition: SortCondition, func: SearchCallbackFunc) => {
const { itemType, subItemType, type } = this.props; if (itemType === '') {
if (itemType === "") {
const res = { total: 0, data: [] }; const res = { total: 0, data: [] };
func(res); func(res);
} else { } else {
ItemUtil.getListByItemType(type, itemType, subItemType, condition, func); ItemUtil.getListByItemType(type, itemType, subItemType, condition, func);
} }
} };
getUrl() { const baseUrl = ItemUtil.getItemTypeSearchUrl(type, itemType, subItemType);
const { itemType, subItemType, type } = this.props;
let url = ItemUtil.getItemTypeSearchUrl(type, itemType, subItemType);
return url;
}
render() {
const { lang, type } = this.props;
const baseUrl = this.getUrl();
return ( return (
<div className="list"> <div className="list">
<h3>{Functions.mlang("[en]Listing item[/en][ja]アイテム一覧[/ja]", lang)}</h3> <h3>{Functions.mlang('[en]Listing item[/en][ja]アイテム一覧[/ja]', lang)}</h3>
<DatabaseListItem lang={lang} url={baseUrl} search={this.searchFunc} type={type} /> <DatabaseListItem lang={lang} url={baseUrl} search={searchFunc} type={type} />
</div> </div>
); );
} };
}
export default DatabaseSearchByItemType; export default DatabaseSearchByItemType;

View File

@ -1,74 +1,41 @@
import React from "react"; import React from 'react';
import { useLocation } from "react-router-dom";
import { BrainAtlasType, MultiLang } from "../config";
import Functions from "../functions";
import DatabaseListItem from "./lib/DatabaseListItem";
import ItemUtil, { KeywordSearchType, SearchCallbackFunc, SortCondition } from "./lib/ItemUtil";
interface PropsFC { import { useLocation } from 'react-router-dom';
import { BrainAtlasType, MultiLang } from '../config';
import Functions from '../functions';
import DatabaseListItem from './lib/DatabaseListItem';
import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil';
interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
interface Props extends PropsFC { const DatabaseSearchByKeyword: React.FC<Props> = (props) => {
location: any; const { lang, type } = props;
}
interface State { const location = useLocation();
type: KeywordSearchType; const query = ItemUtil.getSearchKeywordByQuery(location.search);
keyword: string;
}
class DatabaseSearchByKeyword extends React.Component<Props, State> { const searchFunc = (condition: SortCondition, func: SearchCallbackFunc) => {
constructor(props: Props) { if (query.keyword === '') {
super(props);
const { location } = props;
const { type, keyword } = ItemUtil.getSearchKeywordByQuery(location.search);
this.state = { type, keyword };
this.searchFunc = this.searchFunc.bind(this);
}
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
const { type, keyword } = ItemUtil.getSearchKeywordByQuery(nextProps.location.search);
if (prevState.type !== type || prevState.keyword !== keyword) {
return { type, keyword };
}
return null;
}
getUrl() {
const { type } = this.props;
return ItemUtil.getSearchByKeywordUrl(type, this.state.type, this.state.keyword);
}
searchFunc(condition: SortCondition, func: SearchCallbackFunc) {
const { type } = this.props;
if (this.state.keyword === "") {
const res = { total: 0, data: [] }; const res = { total: 0, data: [] };
func(res); func(res);
} else { } else {
ItemUtil.getListByKeyword(type, this.state.type, this.state.keyword, condition, func); ItemUtil.getListByKeyword(type, query.type, query.keyword, condition, func);
} }
}
render() {
const { lang, type } = this.props;
const baseUrl = this.getUrl();
return (
<div className="list">
<h3>{Functions.mlang("[en]Listing item[/en][ja]アイテム一覧[/ja]", lang)}</h3>
<p>
{Functions.mlang("[en]Search Keyword[/en][ja]検索キーワード[/ja]", lang)} : {this.state.keyword}
</p>
<DatabaseListItem lang={lang} url={baseUrl} search={this.searchFunc} type={type} />
</div>
);
}
}
const DatabaseSearchByKeywordFC: React.FC<PropsFC> = (props: PropsFC) => {
const { lang, type } = props;
return <DatabaseSearchByKeyword lang={lang} type={type} location={useLocation()} />;
}; };
export default DatabaseSearchByKeywordFC; const baseUrl = ItemUtil.getSearchByKeywordUrl(type, query.type, query.keyword);
return (
<div className="list">
<h3>{Functions.mlang('[en]Listing item[/en][ja]アイテム一覧[/ja]', lang)}</h3>
<p>
{Functions.mlang('[en]Search Keyword[/en][ja]検索キーワード[/ja]', lang)} : {query.keyword}
</p>
<DatabaseListItem lang={lang} url={baseUrl} search={searchFunc} type={type} />
</div>
);
};
export default DatabaseSearchByKeyword;

View File

@ -1,14 +1,15 @@
import React from "react"; import React from 'react';
import Config, { BrainAtlasType, MultiLang } from "../config";
import styles from "./DatabaseTop.module.css"; import Config, { BrainAtlasType, MultiLang } from '../config';
import ItemType from "./item-type"; import styles from './DatabaseTop.module.css';
import ItemType from './item-type';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
const DatabaseTop: React.FC<Props> = (props: Props) => { const DatabaseTop: React.FC<Props> = (props) => {
const { lang, type } = props; const { lang, type } = props;
const types: string[][] = []; const types: string[][] = [];
const len = Config.XOONIPS_ITEMTYPES.length; const len = Config.XOONIPS_ITEMTYPES.length;
@ -26,7 +27,9 @@ const DatabaseTop: React.FC<Props> = (props: Props) => {
{value.map((itemType, idx) => { {value.map((itemType, idx) => {
return ( return (
<td key={idx} className={styles.itemType}> <td key={idx} className={styles.itemType}>
{itemType !== "" && <ItemType.Top lang={lang} itemType={"xnp" + itemType} type={type} />} {itemType !== '' && (
<ItemType.Top lang={lang} itemType={'xnp' + itemType} type={type} />
)}
</td> </td>
); );
})} })}

View File

@ -1,121 +1,123 @@
import React from "react"; import React from 'react';
import { Navigate, useLocation } from "react-router-dom";
import PageNotFound from "../common/lib/PageNotFound"; import { Navigate, useLocation } from 'react-router-dom';
import { MultiLang } from "../config"; import PageNotFound from '../common/lib/PageNotFound';
import Functions from "../functions"; import { MultiLang } from '../config';
import Functions from '../functions';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
} }
const DatabaseXoopsPathRedirect: React.FC<Props> = (props: Props) => { const DatabaseXoopsPathRedirect: React.FC<Props> = (props) => {
const { lang } = props; const { lang } = props;
const location = useLocation();
const getRedirectUrl = (): string => { const getRedirectUrl = (): string => {
const location = useLocation(); const pathname = location.pathname || '';
const pathname = location.pathname || "";
const query = new URLSearchParams(location.search); const query = new URLSearchParams(location.search);
const search = new RegExp("^/modules/xoonips(?:/+(.*))?$"); const search = new RegExp('^/modules/xoonips(?:/+(.*))?$');
const matches = pathname.match(search); const matches = pathname.match(search);
if (matches === null) { if (matches === null) {
return ""; return '';
} }
const path = matches[1] || ""; const path = matches[1] || '';
switch (path) { switch (path) {
case "": case '':
case "index.php": { case 'index.php': {
return "/database"; return '/database';
} }
case "detail.php": { case 'detail.php': {
const id = query.get("id"); const id = query.get('id');
if (id !== null) { if (id !== null) {
return "/database/item/id/" + Functions.escape(id); return '/database/item/id/' + Functions.escape(id);
} }
const itemId = query.get("item_id"); const itemId = query.get('item_id');
if (itemId !== null && itemId.match(/^\d+$/) !== null) { if (itemId?.match(/^\d+$/) != null) {
return "/database/item/" + Functions.escape(itemId); return '/database/item/' + Functions.escape(itemId);
} }
return ""; return '';
} }
case "listitem.php": { case 'listitem.php': {
const indexId = query.get("index_id"); const indexId = query.get('index_id');
if (indexId !== null && indexId.match(/^\d+$/) !== null) { if (indexId?.match(/^\d+$/) != null) {
const params = new URLSearchParams(); const params = new URLSearchParams();
const map: any = { [
orderby: { key: "orderby", isNumber: false }, { qKey: 'orderby', pKey: 'orderby', isNumber: false },
order_dir: { key: "order_dir", isNumber: true }, { qKey: 'order_dir', pKey: 'order_dir', isNumber: true },
itemcount: { key: "itemcount", isNumber: true }, { qKey: 'itemcount', pKey: 'itemcount', isNumber: true },
page: { key: "page", isNumber: true }, { qKey: 'page', pKey: 'page', isNumber: true },
}; ].forEach(({ qKey, pKey, isNumber }) => {
for (let k in map) { const v = query.get(qKey);
const v = query.get(k); if (v == null || v.length === 0) {
if (v === null || v.length === 0) { return;
continue;
} }
if (map[k].isNumber && v.match(/^\d+$/) !== null) { if (isNumber && v.match(/^\d+$/) != null) {
continue; return;
}
params.set(map[k].key, v);
} }
params.set(pKey, v);
});
const paramStr = params.toString(); const paramStr = params.toString();
return "/database/list/" + Functions.escape(indexId) + (paramStr.length > 0 ? "?" + paramStr : ""); return (
`/database/list/${Functions.escape(indexId)}` +
(paramStr.length > 0 ? `?${paramStr}` : '')
);
} }
break; break;
} }
case "itemselect.php": { case 'itemselect.php': {
const op = query.get("op"); const op = query.get('op');
if (op === null) { if (op === null) {
break; break;
} }
switch (op) { switch (op) {
case "quicksearch": { case 'quicksearch': {
const keyword = query.get("keyword"); const keyword = query.get('keyword');
const itemType = query.get("search_itemtype"); const itemType = query.get('search_itemtype');
if (keyword === null || itemType === null || keyword === "") { if (keyword === null || itemType === null || keyword === '') {
return ""; return '';
} }
const type = itemType.replace("xnp", ""); const type = itemType.replace('xnp', '');
if (itemType !== "basic" && itemType !== "all" && itemType.match(/^xnp.+/) === null) { if (itemType !== 'basic' && itemType !== 'all' && itemType.match(/^xnp.+/) === null) {
return ""; return '';
} }
const params = new URLSearchParams({ type, keyword }); const params = new URLSearchParams({ type, keyword });
const map: any = { [
orderby: { key: "orderby", isNumber: false }, { qKey: 'orderby', pKey: 'orderby', isNumber: false },
orderdir: { key: "order_dir", isNumber: true }, { qKey: 'orderdir', pKey: 'order_dir', isNumber: true },
item_per_page: { key: "itemcount", isNumber: true }, { qKey: 'item_per_page', pKey: 'itemcount', isNumber: true },
page: { key: "page", isNumber: true }, { qKey: 'page', pKey: 'page', isNumber: true },
}; ].forEach(({ qKey, pKey, isNumber }) => {
for (let k in map) { const v = query.get(qKey);
const v = query.get(k); if (v == null || v.length === 0) {
if (v === null || v.length === 0) { return;
continue;
} }
if (map[k].isNumber && v.match(/^\d+$/) !== null) { if (isNumber && v.match(/^\d+$/) != null) {
continue; return;
} }
params.set(map[k].key, v); params.set(pKey, v);
});
return '/database/search?' + params.toString();
} }
return "/database/search?" + params.toString(); case 'itemtypesearch': {
const itemType = query.get('search_itemtype');
if (itemType?.match(/^xnp.+/) == null) {
return '';
} }
case "itemtypesearch": { const type = itemType.replace('xnp', '');
const itemType = query.get("search_itemtype"); return '/database/search/itemtype/' + Functions.escape(type);
if (itemType === null || itemType.match(/^xnp.+/) === null) {
return "";
} }
const type = itemType.replace("xnp", ""); case 'itemsubtypesearch': {
return "/database/search/itemtype/" + Functions.escape(type); let type = '';
} let subtype = '';
case "itemsubtypesearch": {
let type = "";
let subtype = "";
query.forEach((v, k) => { query.forEach((v, k) => {
if (k.match(/^xnp[a-z]+$/) !== null && !!v) { if (k.match(/^xnp[a-z]+$/) !== null && !!v) {
type = k.replace("xnp", ""); type = k.replace('xnp', '');
return; return;
} }
}); });
if (type === "") { if (type === '') {
return ""; return '';
} }
query.forEach((v, k) => { query.forEach((v, k) => {
if (k.match(`^xnp${type}_.+$`) !== null && !!v) { if (k.match(`^xnp${type}_.+$`) !== null && !!v) {
@ -123,23 +125,28 @@ const DatabaseXoopsPathRedirect: React.FC<Props> = (props: Props) => {
return; return;
} }
}); });
if (subtype === "") { if (subtype === '') {
return ""; return '';
} }
return "/database/search/itemtype/" + Functions.escape(type) + "/" + Functions.escape(subtype); return (
'/database/search/itemtype/' +
Functions.escape(type) +
'/' +
Functions.escape(subtype)
);
} }
} }
return ""; return '';
} }
case "advanced_search.php": { case 'advanced_search.php': {
return "/database/advanced"; return '/database/advanced';
} }
} }
return ""; return '';
}; };
const url = getRedirectUrl(); const url = getRedirectUrl();
if (url === "") { if (url === '') {
return <PageNotFound lang={lang} />; return <PageNotFound lang={lang} />;
} }
return <Navigate to={url} />; return <Navigate to={url} />;

View File

@ -1 +0,0 @@
[{"type":"degu","tree":[{"id":3,"title":"Public","num_of_items":0,"children":[{"id":16,"title":"Degu (Octodon degu)","num_of_items":0,"children":[{"id":24,"title":"The Degu 3D Brain Atlas","num_of_items":4,"children":[{"id":18,"title":"References","num_of_items":0,"children":[]}]}]}]}]},{"type":"jm","tree":[{"id":3,"title":"Public","num_of_items":0,"children":[{"id":7,"title":"Japanese Macaque Monkey","num_of_items":0,"children":[{"id":9,"title":"The MRI Standard Brain of Japanese Macaque Monkey","num_of_items":1,"children":[{"id":44,"title":"References","num_of_items":0,"children":[]}]}]}]}]},{"type":"marmoset","tree":[{"id":3,"title":"Public","num_of_items":0,"children":[{"id":66,"title":"The Marmoset 3D Brain Atlas","num_of_items":4,"children":[{"id":69,"title":"References","num_of_items":0,"children":[]}]},{"id":71,"title":"The Marmoset MRI Standard Brain","num_of_items":1,"children":[{"id":73,"title":"References","num_of_items":0,"children":[]}]}]}]}]

View File

@ -41,13 +41,25 @@
width: 9px; width: 9px;
background: url(../assets/images/tree_line.png); background: url(../assets/images/tree_line.png);
} }
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:not(:last-child)) { .indexTree:global(
.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:not(:last-child)
) {
background-position: -9px 0; background-position: -9px 0;
} }
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:not(:last-child).rc-tree-indent-unit-end) { .indexTree:global(
.rc-tree
.rc-tree-treenode
.rc-tree-indent
.rc-tree-indent-unit:not(:last-child).rc-tree-indent-unit-end
) {
background-position: -18px 0; background-position: -18px 0;
} }
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:last-child.rc-tree-indent-unit-end) { .indexTree:global(
.rc-tree
.rc-tree-treenode
.rc-tree-indent
.rc-tree-indent-unit:last-child.rc-tree-indent-unit-end
) {
background-position: -27px 0; background-position: -27px 0;
} }
@ -69,14 +81,20 @@
.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher_close) { .indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher_close) {
background-position: -32px 0; background-position: -32px 0;
} }
.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher-noop) { .indexTree:global(
.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher-noop
) {
background-position: 0 -20px; background-position: 0 -20px;
cursor: auto; cursor: auto;
} }
.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_open) { .indexTree:global(
.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_open
) {
background-position: -16px -20px; background-position: -16px -20px;
} }
.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_close) { .indexTree:global(
.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_close
) {
background-position: -32px -20px; background-position: -32px -20px;
} }

View File

@ -1,136 +1,133 @@
import Tree from "rc-tree"; import React from 'react';
import { DataNode, EventDataNode } from "rc-tree/lib/interface";
import React, { Key } from "react"; import Tree from 'rc-tree';
import { useNavigate } from "react-router"; import { DataNode, EventDataNode } from 'rc-tree/lib/interface';
import { BrainAtlasType, MultiLang } from "../../config"; import { useNavigate } from 'react-router';
import Functions from "../../functions"; import Loading from '../../common/lib/Loading';
import IndexUtil, { Index, INDEX_ID_PUBLIC } from "../lib/IndexUtil"; import { BrainAtlasType, MultiLang } from '../../config';
import styles from "./IndexTree.module.css"; import Functions from '../../functions';
import IndexUtil, { INDEX_ID_PUBLIC, Index } from '../lib/IndexUtil';
import styles from './IndexTree.module.css';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
type: BrainAtlasType; type: BrainAtlasType;
} }
interface State { const IndexTree: React.FC<Props> = (props) => {
tree: DataNode[]; const { lang, type } = props;
expandableKeys: string[]; const navigate = useNavigate();
expandedKeys: string[];
selectedKeys: number[];
}
class IndexTree extends React.Component<Props, State> { const [tree, setTree] = React.useState<DataNode[]>([]);
constructor(props: Props) { const [keys, setKeys] = React.useState<string[]>([]);
super(props); const [expandedKeys, setExpandedKeys] = React.useState<string[]>([]);
this.handleClickOpenAll = this.handleClickOpenAll.bind(this); const [selectedKeys, setSelectedKeys] = React.useState<number[]>([]);
this.handleClickCloseAll = this.handleClickCloseAll.bind(this);
this.handleExpand = this.handleExpand.bind(this);
this.handleSelect = this.handleSelect.bind(this);
const res = this.load();
this.state = {
tree: res.elements,
expandableKeys: res.keys,
expandedKeys: res.expandedKeys,
selectedKeys: [],
};
}
load() { React.useEffect(() => {
const { lang, type } = this.props; const tree: DataNode[] = [];
let keys: string[] = []; const keys: string[] = [];
let eKeys: string[] = []; const eKeys: string[] = [];
const makeTreeNode = (index: Index, depth: number): DataNode => { const makeTreeNode = (index: Index, depth: number, func: (node: DataNode) => void): void => {
const title = Functions.mlang(index.title, lang) + (index.numOfItems > 0 ? " (" + index.numOfItems + ")" : ""); const title =
const children = IndexUtil.getChildren(type, index.id); Functions.mlang(index.title, lang) +
(index.numOfItems > 0 ? ' (' + index.numOfItems + ')' : '');
IndexUtil.getChildren(type, index.id, (children) => {
if (children.length === 0) { if (children.length === 0) {
return { key: String(index.id), title: title }; func({ key: String(index.id), title: title });
} } else {
const childTreeNodes = children.map((value: Index) => {
return makeTreeNode(value, depth + 1);
});
if (depth < 1) { if (depth < 1) {
eKeys.push(String(index.id)); eKeys.push(String(index.id));
} }
keys.push(String(index.id)); keys.push(String(index.id));
return { key: String(index.id), title: title, children: childTreeNodes }; const childTreeNodes: DataNode[] = [];
}; let called = 0;
let elements: DataNode[] = []; children.forEach((value: Index) => {
const index = IndexUtil.get(type, INDEX_ID_PUBLIC); makeTreeNode(value, depth + 1, (cNode) => {
if (index !== null) { called++;
elements.push(makeTreeNode(index, 0)); childTreeNodes.push(cNode);
if (called === children.length) {
func({ key: String(index.id), title: title, children: childTreeNodes });
} }
return { });
elements: elements,
keys: keys,
expandedKeys: eKeys,
};
}
componentDidUpdate(prevProps: Props, prevState: State) {
const { lang, type } = this.props;
if (prevProps.lang !== lang || prevProps.type !== type) {
const res = this.load();
this.setState({
tree: res.elements,
selectedKeys: [],
}); });
} }
});
};
IndexUtil.get(type, INDEX_ID_PUBLIC, (index) => {
if (index != null) {
makeTreeNode(index, 0, (node) => {
tree.push(node);
setTree(tree);
setKeys(keys);
setExpandedKeys(eKeys);
setSelectedKeys([]);
});
} }
});
}, [lang, type]);
handleClickOpenAll() { const handleClickOpenAll = () => {
this.setState({ expandedKeys: this.state.expandableKeys }); setExpandedKeys(keys);
} };
handleClickCloseAll() { const handleClickCloseAll = () => {
this.setState({ expandedKeys: [] }); setExpandedKeys([]);
} };
handleExpand( const handleExpand: (
expandedKeys: Key[], expandedKeys: React.Key[],
info: { info: {
node: EventDataNode<DataNode>; node: EventDataNode<DataNode>;
expanded: boolean; expanded: boolean;
nativeEvent: MouseEvent; nativeEvent: MouseEvent;
} },
): void { ) => void = (expandedKeys) => {
const keys: string[] = expandedKeys.map((key) => { const keys: string[] = expandedKeys.map((key) => {
return typeof key === "string" ? key : String(key); return typeof key === 'string' ? key : String(key);
}); });
this.setState({ expandedKeys: keys }); setExpandedKeys(keys);
} };
handleSelect( const handleSelect: (
selectedKeys: Key[], selectedKeys: React.Key[],
info: { info: {
event: "select"; event: 'select';
selected: boolean; selected: boolean;
node: EventDataNode<DataNode>; node: EventDataNode<DataNode>;
selectedNodes: DataNode[]; selectedNodes: DataNode[];
nativeEvent: MouseEvent; nativeEvent: MouseEvent;
} },
): void { ) => void = (selectedKeys) => {
const navigate = useNavigate(); const selectedKey = selectedKeys.shift() ?? 0;
const { type } = this.props; const key = typeof selectedKey === 'string' ? parseInt(selectedKey, 10) : selectedKey;
const selectedKey = selectedKeys.shift() || 0;
const key = typeof selectedKey === "string" ? parseInt(selectedKey, 10) : selectedKey;
const url = IndexUtil.getUrl(type, key); const url = IndexUtil.getUrl(type, key);
navigate(url); navigate(url);
this.setState({ selectedKeys: [] }); setSelectedKeys([]);
};
if (tree.length === 0) {
return <Loading />;
} }
render() {
return ( return (
<div className={styles.container}> <div className={styles.container}>
<button className={styles.formButton} onClick={this.handleClickOpenAll}> <button className={styles.formButton} onClick={handleClickOpenAll}>
open all open all
</button> </button>
<button className={styles.formButton} onClick={this.handleClickCloseAll}> <button className={styles.formButton} onClick={handleClickCloseAll}>
close all close all
</button> </button>
<Tree className={styles.indexTree} expandedKeys={this.state.expandedKeys} selectedKeys={this.state.selectedKeys} onExpand={this.handleExpand} onSelect={this.handleSelect} showIcon={false} treeData={this.state.tree} /> <Tree
className={styles.indexTree}
expandedKeys={expandedKeys}
selectedKeys={selectedKeys}
onExpand={handleExpand}
onSelect={handleSelect}
showIcon={false}
treeData={tree}
/>
</div> </div>
); );
} };
}
export default IndexTree; export default IndexTree;

View File

@ -1,22 +1,28 @@
import AdvancedSearchBase, { AdvancedSearchBaseProps } from "../lib/AdvancedSearchBase"; import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
class BinderAdvancedSearch extends AdvancedSearchBase { class BinderAdvancedSearch extends AdvancedSearchBase {
constructor(props: AdvancedSearchBaseProps) { constructor(props: AdvancedSearchBaseProps) {
super(props); super(props);
this.type = "binder"; this.type = 'binder';
this.title = "Binder"; this.title = 'Binder';
this.state.values["title"] = ""; this.state.values.title = '';
this.state.values["keyword"] = ""; this.state.values.keyword = '';
this.state.values["description"] = ""; this.state.values.description = '';
this.state.values["doi"] = ""; this.state.values.doi = '';
} }
getRows() { getRows() {
const rows = [ const rows = [
{ label: "[en]Title[/en][ja]タイトル[/ja]", value: this.renderFieldInputText("title", 50) }, { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) },
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: this.renderFieldInputText("keyword", 50) }, {
{ label: "[en]Description[/en][ja]概要[/ja]", value: this.renderFieldInputText("description", 50) }, label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
{ label: "ID", value: this.renderFieldInputText("doi", 50) }, value: this.renderFieldInputText('keyword', 50),
},
{
label: '[en]Description[/en][ja]概要[/ja]',
value: this.renderFieldInputText('description', 50),
},
{ label: 'ID', value: this.renderFieldInputText('doi', 50) },
]; ];
return rows; return rows;
} }

View File

@ -1,10 +1,11 @@
import React from "react"; import React from 'react';
import ItemType from "..";
import { BrainAtlasType, MultiLang } from "../../../config"; import ItemType from '..';
import Functions from "../../../functions"; import { BrainAtlasType, MultiLang } from '../../../config';
import ItemUtil, { Item, ItemBinder } from "../../lib/ItemUtil"; import Functions from '../../../functions';
import DetailBase from "../lib/DetailBase"; import ItemUtil, { Item, ItemBinder } from '../../lib/ItemUtil';
import ItemTypeField from "../lib/field"; import DetailBase from '../lib/DetailBase';
import ItemTypeField from '../lib/field';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -12,46 +13,32 @@ interface Props {
type: BrainAtlasType; type: BrainAtlasType;
} }
interface State { const BinderLinkItems: React.FC<Props> = (props) => {
items: Item[]; const { lang, item, type } = props;
} const [items, setItems] = React.useState<Item[]>([]);
class BinderLinkItems extends React.Component<Props, State> { const isMounted = React.useRef<boolean>(false);
constructor(props: Props) { React.useEffect(() => {
super(props); isMounted.current = true;
this.state = { return () => {
items: [], isMounted.current = false;
}; };
} }, []);
componentDidMount() { React.useEffect(() => {
this.updateItems();
}
componentDidUpdate(prevProps: Props, prevState: State) {
const prevItemIds = prevProps.item.item_link;
const nextItemIds = this.props.item.item_link;
if (prevItemIds.toString() !== nextItemIds.toString()) {
this.updateItems();
}
}
updateItems() {
const { item, type } = this.props;
const itemIds = item.item_link; const itemIds = item.item_link;
ItemUtil.getList(type, itemIds, (results) => { ItemUtil.getList(type, itemIds, (results) => {
const items = results.data; if (isMounted.current) {
this.setState({ items }); setItems(results.data);
});
} }
});
}, [item.item_link, type]);
render() {
const { lang, type } = this.props;
return ( return (
<table className="listTable"> <table className="listTable">
<tbody> <tbody>
{this.state.items.map((item, idx) => { {items.map((item, idx) => {
const evenodd = idx % 2 ? "even" : "odd"; const evenodd = idx % 2 ? 'even' : 'odd';
return ( return (
<tr key={item.item_id}> <tr key={item.item_id}>
<td className={evenodd}> <td className={evenodd}>
@ -63,24 +50,44 @@ class BinderLinkItems extends React.Component<Props, State> {
</tbody> </tbody>
</table> </table>
); );
} };
}
class BinderDetail extends DetailBase { class BinderDetail extends DetailBase {
getFields() { getFields() {
const { lang, type } = this.props; const { lang, type } = this.props;
const item = this.props.item as ItemBinder; const item = this.props.item as ItemBinder;
return [ return [
{ label: "ID", value: item.doi }, { label: 'ID', value: item.doi },
{ label: "[en]Title[/en][ja]タイトル[/ja]", value: Functions.mlang(item.title, lang) }, { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) },
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} /> }, {
{ label: "[en]Description[/en][ja]概要[/ja]", value: <ItemTypeField.Description lang={lang} description={item.description} /> }, label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
{ label: "[en]Last Modified Date[/en][ja]最終更新日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} /> }, value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} />,
{ label: "[en]Created Date[/en][ja]作成日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} /> }, },
{ label: "[en]Contributor[/en][ja]登録者[/ja]", value: <ItemTypeField.Contributer lang={lang} uname={item.uname} name={item.name} /> }, {
{ label: "[en]Item Type[/en][ja]アイテムタイプ[/ja]", value: item.item_type_display_name }, label: '[en]Description[/en][ja]概要[/ja]',
{ label: "[en]Change Log(History)[/en][ja]変更履歴[/ja]", value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} /> }, value: <ItemTypeField.Description lang={lang} description={item.description} />,
{ label: "Index", value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} /> }, },
{
label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} />,
},
{
label: '[en]Created Date[/en][ja]作成日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} />,
},
{
label: '[en]Contributor[/en][ja]登録者[/ja]',
value: <ItemTypeField.Contributor lang={lang} uname={item.uname} name={item.name} />,
},
{ label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name },
{
label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]',
value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} />,
},
{
label: 'Index',
value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} />,
},
]; ];
} }

View File

@ -1,14 +1,13 @@
import React from "react"; import { Link } from 'react-router-dom';
import { Link } from "react-router-dom"; import Functions from '../../../functions';
import Functions from "../../../functions"; import iconFile from '../../assets/images/icon_binder.gif';
import iconFile from "../../assets/images/icon_binder.gif"; import { ItemBinder } from '../../lib/ItemUtil';
import { ItemBinder } from "../../lib/ItemUtil"; import ListBase, { ListBaseProps } from '../lib/ListBase';
import ListBase, { ListBaseProps } from "../lib/ListBase";
class BinderList extends ListBase { class BinderList extends ListBase {
constructor(props: ListBaseProps) { constructor(props: ListBaseProps) {
super(props); super(props);
this.label = "Binder"; this.label = 'Binder';
this.icon = iconFile; this.icon = iconFile;
} }

View File

@ -1,13 +1,13 @@
import iconFile from "../../assets/images/icon_binder.gif"; import iconFile from '../../assets/images/icon_binder.gif';
import TopBase, { TopBaseProps } from "../lib/TopBase"; import TopBase, { TopBaseProps } from '../lib/TopBase';
class BinderTop extends TopBase { class BinderTop extends TopBase {
constructor(props: TopBaseProps) { constructor(props: TopBaseProps) {
super(props); super(props);
this.type = "binder"; this.type = 'binder';
this.label = "Binder"; this.label = 'Binder';
this.icon = iconFile; this.icon = iconFile;
this.description = "[en]Binder collection.[/en][ja]バインダー[/ja]"; this.description = '[en]Binder collection.[/en][ja]バインダー[/ja]';
} }
} }

View File

@ -1,7 +1,7 @@
import BinderAdvancedSearch from "./BinderAdvancedSearch"; import BinderAdvancedSearch from './BinderAdvancedSearch';
import BinderDetail from "./BinderDetail"; import BinderDetail from './BinderDetail';
import BinderList from "./BinderList"; import BinderList from './BinderList';
import BinderTop from "./BinderTop"; import BinderTop from './BinderTop';
const ItemTypeBinder = { const ItemTypeBinder = {
Top: BinderTop, Top: BinderTop,

View File

@ -1,34 +1,52 @@
import AdvancedSearchBase, { AdvancedSearchBaseProps } from "../lib/AdvancedSearchBase"; import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
class BookAdvancedSearch extends AdvancedSearchBase { class BookAdvancedSearch extends AdvancedSearchBase {
constructor(props: AdvancedSearchBaseProps) { constructor(props: AdvancedSearchBaseProps) {
super(props); super(props);
this.type = "book"; this.type = 'book';
this.title = "Book"; this.title = 'Book';
this.state.values["title"] = ""; this.state.values.title = '';
this.state.values["keyword"] = ""; this.state.values.keyword = '';
this.state.values["description"] = ""; this.state.values.description = '';
this.state.values["doi"] = ""; this.state.values.doi = '';
this.state.values["author"] = ""; this.state.values.author = '';
this.state.values["editor"] = ""; this.state.values.editor = '';
this.state.values["publisher"] = ""; this.state.values.publisher = '';
this.state.values["publication_year"] = ""; this.state.values.publication_year = '';
this.state.values["isbn"] = ""; this.state.values.isbn = '';
this.state.values["file.book_pdf.original_file_name"] = ""; this.state.values['file.book_pdf.original_file_name'] = '';
} }
getRows() { getRows() {
const rows = [ const rows = [
{ label: "[en]Book Title[/en][ja]著書名[/ja]", value: this.renderFieldInputText("title", 50) }, {
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: this.renderFieldInputText("keyword", 50) }, label: '[en]Book Title[/en][ja]著書名[/ja]',
{ label: "[en]Description[/en][ja]概要[/ja]", value: this.renderFieldInputText("description", 50) }, value: this.renderFieldInputText('title', 50),
{ label: "ID", value: this.renderFieldInputText("doi", 50) }, },
{ label: "[en]Author[/en][ja]著者[/ja]", value: this.renderFieldInputText("author", 50) }, {
{ label: "[en]Editor[/en][ja]編集者[/ja]", value: this.renderFieldInputText("editor", 50) }, label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
{ label: "[en]Publisher[/en][ja]出版社[/ja]", value: this.renderFieldInputText("publisher", 50) }, value: this.renderFieldInputText('keyword', 50),
{ label: "[en]Publication Year[/en][ja]出版年[/ja]", value: this.renderFieldInputText("publication_year", 10) }, },
{ label: "ISBN", value: this.renderFieldInputText("isbn", 50) }, {
{ label: "[en]PDF File[/en][ja]PDF ファイル[/ja]", value: this.renderFieldInputText("file.book_pdf.original_file_name", 50) }, label: '[en]Description[/en][ja]概要[/ja]',
value: this.renderFieldInputText('description', 50),
},
{ label: 'ID', value: this.renderFieldInputText('doi', 50) },
{ label: '[en]Author[/en][ja]著者[/ja]', value: this.renderFieldInputText('author', 50) },
{ label: '[en]Editor[/en][ja]編集者[/ja]', value: this.renderFieldInputText('editor', 50) },
{
label: '[en]Publisher[/en][ja]出版社[/ja]',
value: this.renderFieldInputText('publisher', 50),
},
{
label: '[en]Publication Year[/en][ja]出版年[/ja]',
value: this.renderFieldInputText('publication_year', 10),
},
{ label: 'ISBN', value: this.renderFieldInputText('isbn', 50) },
{
label: '[en]PDF File[/en][ja]PDF ファイル[/ja]',
value: this.renderFieldInputText('file.book_pdf.original_file_name', 50),
},
]; ];
return rows; return rows;
} }

View File

@ -1,39 +1,79 @@
import React from "react"; import Functions from '../../../functions';
import Functions from "../../../functions"; import { ItemBook } from '../../lib/ItemUtil';
import { ItemBook } from "../../lib/ItemUtil"; import DetailBase from '../lib/DetailBase';
import DetailBase from "../lib/DetailBase"; import ItemTypeField from '../lib/field';
import ItemTypeField from "../lib/field";
class BookDetail extends DetailBase { class BookDetail extends DetailBase {
getFields() { getFields() {
const { lang, type } = this.props; const { lang, type } = this.props;
const item = this.props.item as ItemBook; const item = this.props.item as ItemBook;
return [ return [
{ label: "ID", value: item.doi }, { label: 'ID', value: item.doi },
{ label: "[en]Language[/en][ja]言語[/ja]", value: <ItemTypeField.Language lang={lang} itemLang={item.lang} /> },
{ label: "[en]Book Title[/en][ja]著書名[/ja]", value: Functions.mlang(item.title, lang) },
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} /> },
{ label: "[en]Description[/en][ja]概要[/ja]", value: <ItemTypeField.Description lang={lang} description={item.description} /> },
{ label: "[en]Last Modified Date[/en][ja]最終更新日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} /> },
{ label: "[en]Created Date[/en][ja]作成日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} /> },
{ label: "[en]Contributor[/en][ja]登録者[/ja]", value: <ItemTypeField.Contributer lang={lang} uname={item.uname} name={item.name} /> },
{ label: "[en]Item Type[/en][ja]アイテムタイプ[/ja]", value: item.item_type_display_name },
{ label: "[en]Change Log(History)[/en][ja]変更履歴[/ja]", value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} /> },
{ label: "[en]Author[/en][ja]著者[/ja]", value: <ItemTypeField.Author lang={lang} author={item.author} /> },
{ label: "[en]Editor[/en][ja]編集者[/ja]", value: Functions.mlang(item.editor, lang) },
{ label: "[en]Publisher[/en][ja]出版社[/ja]", value: Functions.mlang(item.publisher, lang) },
{ label: "[en]Publication Year[/en][ja]出版年[/ja]", value: item.publication_year },
{ {
label: "URL", label: '[en]Language[/en][ja]言語[/ja]',
value: <ItemTypeField.Language lang={lang} itemLang={item.lang} />,
},
{ label: '[en]Book Title[/en][ja]著書名[/ja]', value: Functions.mlang(item.title, lang) },
{
label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} />,
},
{
label: '[en]Description[/en][ja]概要[/ja]',
value: <ItemTypeField.Description lang={lang} description={item.description} />,
},
{
label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} />,
},
{
label: '[en]Created Date[/en][ja]作成日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} />,
},
{
label: '[en]Contributor[/en][ja]登録者[/ja]',
value: <ItemTypeField.Contributor lang={lang} uname={item.uname} name={item.name} />,
},
{ label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name },
{
label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]',
value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} />,
},
{
label: '[en]Author[/en][ja]著者[/ja]',
value: <ItemTypeField.Author lang={lang} author={item.author} />,
},
{ label: '[en]Editor[/en][ja]編集者[/ja]', value: Functions.mlang(item.editor, lang) },
{ label: '[en]Publisher[/en][ja]出版社[/ja]', value: Functions.mlang(item.publisher, lang) },
{ label: '[en]Publication Year[/en][ja]出版年[/ja]', value: item.publication_year },
{
label: 'URL',
value: ( value: (
<a href={item.url} target="_blank" rel="noopener noreferrer"> <a href={item.url} target="_blank" rel="noopener noreferrer">
{item.url} {item.url}
</a> </a>
), ),
}, },
{ label: "[en]PDF File[/en][ja]PDF ファイル[/ja]", value: <ItemTypeField.ItemFile lang={lang} file={item.file} ftype="book_pdf" downloadLimit={item.attachment_dl_limit} type={type} /> }, {
{ label: "Index", value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} /> }, label: '[en]PDF File[/en][ja]PDF ファイル[/ja]',
{ label: "[en]Related to[/en][ja]関連アイテム[/ja]", value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} /> }, value: (
<ItemTypeField.ItemFile
lang={lang}
file={item.file}
fileType="book_pdf"
downloadLimit={item.attachment_dl_limit}
type={type}
/>
),
},
{
label: 'Index',
value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} />,
},
{
label: '[en]Related to[/en][ja]関連アイテム[/ja]',
value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} />,
},
]; ];
} }
} }

View File

@ -1,14 +1,14 @@
import React, { Fragment } from "react"; import { Fragment } from 'react';
import { Link } from "react-router-dom"; import { Link } from 'react-router-dom';
import Functions from "../../../functions"; import Functions from '../../../functions';
import iconFile from "../../assets/images/icon_book.gif"; import iconFile from '../../assets/images/icon_book.gif';
import { ItemBook } from "../../lib/ItemUtil"; import { ItemBook } from '../../lib/ItemUtil';
import ListBase, { ListBaseProps } from "../lib/ListBase"; import ListBase, { ListBaseProps } from '../lib/ListBase';
class BookList extends ListBase { class BookList extends ListBase {
constructor(props: ListBaseProps) { constructor(props: ListBaseProps) {
super(props); super(props);
this.label = "Book"; this.label = 'Book';
this.icon = iconFile; this.icon = iconFile;
} }
@ -18,7 +18,7 @@ class BookList extends ListBase {
const authors = item.author.map((author, i) => { const authors = item.author.map((author, i) => {
return ( return (
<Fragment key={i}> <Fragment key={i}>
{i > 0 && ", "} {i > 0 && ', '}
{Functions.mlang(author, lang)} {Functions.mlang(author, lang)}
</Fragment> </Fragment>
); );

View File

@ -1,13 +1,13 @@
import iconFile from "../../assets/images/icon_book.gif"; import iconFile from '../../assets/images/icon_book.gif';
import TopBase, { TopBaseProps } from "../lib/TopBase"; import TopBase, { TopBaseProps } from '../lib/TopBase';
class BookTop extends TopBase { class BookTop extends TopBase {
constructor(props: TopBaseProps) { constructor(props: TopBaseProps) {
super(props); super(props);
this.type = "book"; this.type = 'book';
this.label = "Book"; this.label = 'Book';
this.icon = iconFile; this.icon = iconFile;
this.description = "[en]Related book collection.[/en][ja]関連書籍[/ja]"; this.description = '[en]Related book collection.[/en][ja]関連書籍[/ja]';
} }
} }

View File

@ -1,7 +1,7 @@
import BookAdvancedSearch from "./BookAdvancedSearch"; import BookAdvancedSearch from './BookAdvancedSearch';
import BookDetail from "./BookDetail"; import BookDetail from './BookDetail';
import BookList from "./BookList"; import BookList from './BookList';
import BookTop from "./BookTop"; import BookTop from './BookTop';
const ItemTypeBook = { const ItemTypeBook = {
Top: BookTop, Top: BookTop,

View File

@ -1,48 +1,67 @@
import React from "react"; import { ItemConferenceSubTypes } from '../../lib/ItemUtil';
import { ItemConferenceSubTypes } from "../../lib/ItemUtil"; import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
import AdvancedSearchBase, { AdvancedSearchBaseProps } from "../lib/AdvancedSearchBase";
class ConferenceAdvancedSearch extends AdvancedSearchBase { class ConferenceAdvancedSearch extends AdvancedSearchBase {
constructor(props: AdvancedSearchBaseProps) { constructor(props: AdvancedSearchBaseProps) {
super(props); super(props);
this.type = "conference"; this.type = 'conference';
this.title = "Conference"; this.title = 'Conference';
const now = new Date(); const now = new Date();
const year = String(now.getFullYear()); const year = String(now.getFullYear());
const month = String(now.getMonth() + 1); const month = String(now.getMonth() + 1);
const mday = String(now.getDate()); const mday = String(now.getDate());
this.state.values["title"] = ""; this.state.values.title = '';
this.state.values["presentation_type"] = ""; this.state.values.presentation_type = '';
this.state.values["author"] = ""; this.state.values.author = '';
this.state.values["conference_from_year"] = year; this.state.values.conference_from_year = year;
this.state.values["conference_from_month"] = month; this.state.values.conference_from_month = month;
this.state.values["conference_from_mday"] = mday; this.state.values.conference_from_mday = mday;
this.state.values["conference_to_year"] = year; this.state.values.conference_to_year = year;
this.state.values["conference_to_month"] = month; this.state.values.conference_to_month = month;
this.state.values["conference_to_mday"] = mday; this.state.values.conference_to_mday = mday;
this.setIgnoreKey("conference_from_year"); this.setIgnoreKey('conference_from_year');
this.setIgnoreKey("conference_from_month"); this.setIgnoreKey('conference_from_month');
this.setIgnoreKey("conference_from_mday"); this.setIgnoreKey('conference_from_mday');
this.setIgnoreKey("conference_to_year"); this.setIgnoreKey('conference_to_year');
this.setIgnoreKey("conference_to_month"); this.setIgnoreKey('conference_to_month');
this.setIgnoreKey("conference_to_mday"); this.setIgnoreKey('conference_to_mday');
} }
renderDate() { renderDate() {
return ( return (
<> <>
<div>{this.renderFieldDate("From", "conference_from_year", "conference_from_month", "conference_from_mday")}</div> <div>
<div>{this.renderFieldDate("To", "conference_to_year", "conference_to_month", "conference_to_mday")}</div> {this.renderFieldDate(
'From',
'conference_from_year',
'conference_from_month',
'conference_from_mday',
)}
</div>
<div>
{this.renderFieldDate(
'To',
'conference_to_year',
'conference_to_month',
'conference_to_mday',
)}
</div>
</> </>
); );
} }
getRows() { getRows() {
const rows = [ const rows = [
{ label: "[en]Presentation Title[/en][ja]発表議題[/ja]", value: this.renderFieldInputText("title", 50) }, {
{ label: "[en]Presentation Type[/en][ja]発表資料ファイル形式[/ja]", value: this.renderFieldSelect("presentation_type", ItemConferenceSubTypes) }, label: '[en]Presentation Title[/en][ja]発表議題[/ja]',
{ label: "[en]Author[/en][ja]発表者[/ja]", value: this.renderFieldInputText("author", 50) }, value: this.renderFieldInputText('title', 50),
{ label: "[en]Date[/en][ja]日付[/ja]", value: this.renderDate() }, },
{
label: '[en]Presentation Type[/en][ja]発表資料ファイル形式[/ja]',
value: this.renderFieldSelect('presentation_type', ItemConferenceSubTypes),
},
{ label: '[en]Author[/en][ja]発表者[/ja]', value: this.renderFieldInputText('author', 50) },
{ label: '[en]Date[/en][ja]日付[/ja]', value: this.renderDate() },
]; ];
return rows; return rows;
} }

View File

@ -1,33 +1,91 @@
import React from "react"; import Functions from '../../../functions';
import Functions from "../../../functions"; import { ItemConference } from '../../lib/ItemUtil';
import { ItemConference } from "../../lib/ItemUtil"; import DetailBase from '../lib/DetailBase';
import DetailBase from "../lib/DetailBase"; import ItemTypeField from '../lib/field';
import ItemTypeField from "../lib/field"; import ConferenceUtil from './ConferenceUtil';
import ConferenceUtil from "./ConferenceUtil";
class ConferenceDetail extends DetailBase { class ConferenceDetail extends DetailBase {
getFields() { getFields() {
const { lang, type } = this.props; const { lang, type } = this.props;
const item = this.props.item as ItemConference; const item = this.props.item as ItemConference;
return [ return [
{ label: "ID", value: item.doi }, { label: 'ID', value: item.doi },
{ label: "[en]Language[/en][ja]言語[/ja]", value: <ItemTypeField.Language lang={lang} itemLang={item.lang} /> }, {
{ label: "[en]Conference Title[/en][ja]学会名[/ja]", value: Functions.mlang(item.conference_title, lang) }, label: '[en]Language[/en][ja]言語[/ja]',
{ label: "[en]Place[/en][ja]開催地[/ja]", value: item.place }, value: <ItemTypeField.Language lang={lang} itemLang={item.lang} />,
{ label: "[en]Date[/en][ja]日付[/ja]", value: <ConferenceUtil.ConferenceDate lang={lang} item={item} /> }, },
{ label: "[en]Last Modified Date[/en][ja]最終更新日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} /> }, {
{ label: "[en]Created Date[/en][ja]作成日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} /> }, label: '[en]Conference Title[/en][ja]学会名[/ja]',
{ label: "[en]Contributor[/en][ja]登録者[/ja]", value: <ItemTypeField.Contributer lang={lang} uname={item.uname} name={item.name} /> }, value: Functions.mlang(item.conference_title, lang),
{ label: "[en]Item Type[/en][ja]アイテムタイプ[/ja]", value: item.item_type_display_name }, },
{ label: "[en]Change Log(History)[/en][ja]変更履歴[/ja]", value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} /> }, { label: '[en]Place[/en][ja]開催地[/ja]', value: item.place },
{ label: "[en]Presentation Title[/en][ja]発表議題[/ja]", value: Functions.mlang(item.title, lang) }, {
{ label: "[en]Author[/en][ja]発表者[/ja]", value: <ItemTypeField.Author lang={lang} author={item.author} /> }, label: '[en]Date[/en][ja]日付[/ja]',
{ label: "[en]Abstract[/en][ja]要約[/ja]", value: <ItemTypeField.Description lang={lang} description={item.abstract} /> }, value: <ConferenceUtil.ConferenceDate lang={lang} item={item} />,
{ label: "[en]Presentation File[/en][ja]発表資料[/ja]", value: <ItemTypeField.ItemFile lang={lang} file={item.file} ftype="conference_file" type={type} /> }, },
{ label: "[en]Presentation Type[/en][ja]発表資料ファイル形式[/ja]", value: <ConferenceUtil.PresentationType lang={lang} type={item.presentation_type} /> }, {
{ label: "[en]Conference Paper[/en][ja]学会資料[/ja]", value: <ItemTypeField.ItemFile lang={lang} file={item.file} ftype="conference_paper" type={type} /> }, label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]',
{ label: "Index", value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} /> }, value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} />,
{ label: "[en]Related to[/en][ja]関連アイテム[/ja]", value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} /> }, },
{
label: '[en]Created Date[/en][ja]作成日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} />,
},
{
label: '[en]Contributor[/en][ja]登録者[/ja]',
value: <ItemTypeField.Contributor lang={lang} uname={item.uname} name={item.name} />,
},
{ label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name },
{
label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]',
value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} />,
},
{
label: '[en]Presentation Title[/en][ja]発表議題[/ja]',
value: Functions.mlang(item.title, lang),
},
{
label: '[en]Author[/en][ja]発表者[/ja]',
value: <ItemTypeField.Author lang={lang} author={item.author} />,
},
{
label: '[en]Abstract[/en][ja]要約[/ja]',
value: <ItemTypeField.Description lang={lang} description={item.abstract} />,
},
{
label: '[en]Presentation File[/en][ja]発表資料[/ja]',
value: (
<ItemTypeField.ItemFile
lang={lang}
file={item.file}
fileType="conference_file"
type={type}
/>
),
},
{
label: '[en]Presentation Type[/en][ja]発表資料ファイル形式[/ja]',
value: <ConferenceUtil.PresentationType lang={lang} type={item.presentation_type} />,
},
{
label: '[en]Conference Paper[/en][ja]学会資料[/ja]',
value: (
<ItemTypeField.ItemFile
lang={lang}
file={item.file}
fileType="conference_paper"
type={type}
/>
),
},
{
label: 'Index',
value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} />,
},
{
label: '[en]Related to[/en][ja]関連アイテム[/ja]',
value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} />,
},
]; ];
} }
} }

View File

@ -1,15 +1,16 @@
import React, { Fragment } from "react"; import React from 'react';
import { Link } from "react-router-dom";
import Functions from "../../../functions"; import { Link } from 'react-router-dom';
import iconFile from "../../assets/images/icon_conference.gif"; import Functions from '../../../functions';
import { ItemConference } from "../../lib/ItemUtil"; import iconFile from '../../assets/images/icon_conference.gif';
import ListBase, { ListBaseProps } from "../lib/ListBase"; import { ItemConference } from '../../lib/ItemUtil';
import ConferenceUtil from "./ConferenceUtil"; import ListBase, { ListBaseProps } from '../lib/ListBase';
import ConferenceUtil from './ConferenceUtil';
class ConferenceList extends ListBase { class ConferenceList extends ListBase {
constructor(props: ListBaseProps) { constructor(props: ListBaseProps) {
super(props); super(props);
this.label = "Conference"; this.label = 'Conference';
this.icon = iconFile; this.icon = iconFile;
} }
@ -18,17 +19,18 @@ class ConferenceList extends ListBase {
const item = this.props.item as ItemConference; const item = this.props.item as ItemConference;
const authors = item.author.map((author, i) => { const authors = item.author.map((author, i) => {
return ( return (
<Fragment key={i}> <React.Fragment key={i}>
{i > 0 && ", "} {i > 0 && ', '}
{Functions.mlang(author, lang)} {Functions.mlang(author, lang)}
</Fragment> </React.Fragment>
); );
}); });
return ( return (
<> <>
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link> <Link to={this.url}>{Functions.mlang(item.title, lang)}</Link>
<br /> <br />
{Functions.mlang(item.conference_title, lang)} (<ConferenceUtil.PresentationType lang={lang} type={item.presentation_type} />)<br /> {Functions.mlang(item.conference_title, lang)} (
<ConferenceUtil.PresentationType lang={lang} type={item.presentation_type} />)<br />
{authors} {authors}
</> </>
); );

View File

@ -1,14 +1,14 @@
import iconFile from "../../assets/images/icon_conference.gif"; import iconFile from '../../assets/images/icon_conference.gif';
import { ItemConferenceSubTypes } from "../../lib/ItemUtil"; import { ItemConferenceSubTypes } from '../../lib/ItemUtil';
import TopBase, { TopBaseProps } from "../lib/TopBase"; import TopBase, { TopBaseProps } from '../lib/TopBase';
class ConferenceTop extends TopBase { class ConferenceTop extends TopBase {
constructor(props: TopBaseProps) { constructor(props: TopBaseProps) {
super(props); super(props);
this.type = "conference"; this.type = 'conference';
this.label = "Conference"; this.label = 'Conference';
this.icon = iconFile; this.icon = iconFile;
this.description = "[en]Electrical presentation files for conference.[/en][ja]学会発表[/ja]"; this.description = '[en]Electrical presentation files for conference.[/en][ja]学会発表[/ja]';
this.subTypes = ItemConferenceSubTypes; this.subTypes = ItemConferenceSubTypes;
} }
} }

View File

@ -1,6 +1,6 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../config"; import { MultiLang } from '../../../config';
import { ItemConference, ItemConferenceSubType, ItemConferenceSubTypes } from "../../lib/ItemUtil"; import { ItemConference, ItemConferenceSubType, ItemConferenceSubTypes } from '../../lib/ItemUtil';
interface PresentationTypeProps { interface PresentationTypeProps {
lang: MultiLang; lang: MultiLang;
@ -12,7 +12,7 @@ const PresentationType: React.FC<PresentationTypeProps> = (props: PresentationTy
const subtype = ItemConferenceSubTypes.find((value) => { const subtype = ItemConferenceSubTypes.find((value) => {
return value.type === type; return value.type === type;
}); });
if (typeof subtype === "undefined") { if (typeof subtype === 'undefined') {
return null; return null;
} }
return <span>{subtype.label}</span>; return <span>{subtype.label}</span>;
@ -25,9 +25,34 @@ interface ConferenceDateProps {
const ConferenceDate: React.FC<ConferenceDateProps> = (props: ConferenceDateProps) => { const ConferenceDate: React.FC<ConferenceDateProps> = (props: ConferenceDateProps) => {
const { item } = props; const { item } = props;
const monthStr = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; const monthStr = [
const from = "From: " + monthStr[item.conference_from_month - 1] + " " + item.conference_from_mday + ", " + item.conference_from_year; 'Jan',
const to = "To: " + monthStr[item.conference_to_month - 1] + " " + item.conference_to_mday + ", " + item.conference_to_year; 'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
const from =
'From: ' +
monthStr[item.conference_from_month - 1] +
' ' +
item.conference_from_mday +
', ' +
item.conference_from_year;
const to =
'To: ' +
monthStr[item.conference_to_month - 1] +
' ' +
item.conference_to_mday +
', ' +
item.conference_to_year;
return ( return (
<span> <span>
{from} {to} {from} {to}

View File

@ -1,7 +1,7 @@
import ConferenceAdvancedSearch from "./ConferenceAdvancedSearch"; import ConferenceAdvancedSearch from './ConferenceAdvancedSearch';
import ConferenceDetail from "./ConferenceDetail"; import ConferenceDetail from './ConferenceDetail';
import ConferenceList from "./ConferenceList"; import ConferenceList from './ConferenceList';
import ConferenceTop from "./ConferenceTop"; import ConferenceTop from './ConferenceTop';
const ItemTypeConference = { const ItemTypeConference = {
Top: ConferenceTop, Top: ConferenceTop,

View File

@ -1,42 +1,68 @@
import { ItemDataSubTypes } from "../../lib/ItemUtil"; import { ItemDataSubTypes } from '../../lib/ItemUtil';
import AdvancedSearchBase, { AdvancedSearchBaseProps } from "../lib/AdvancedSearchBase"; import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
class DataAdvancedSearch extends AdvancedSearchBase { class DataAdvancedSearch extends AdvancedSearchBase {
constructor(props: AdvancedSearchBaseProps) { constructor(props: AdvancedSearchBaseProps) {
super(props); super(props);
this.type = "data"; this.type = 'data';
this.title = "Data"; this.title = 'Data';
const now = new Date(); const now = new Date();
const year = String(now.getFullYear()); const year = String(now.getFullYear());
const month = String(now.getMonth() + 1); const month = String(now.getMonth() + 1);
const mday = String(now.getDate()); const mday = String(now.getDate());
this.state.values["title"] = ""; this.state.values.title = '';
this.state.values["keyword"] = ""; this.state.values.keyword = '';
this.state.values["description"] = ""; this.state.values.description = '';
this.state.values["doi"] = ""; this.state.values.doi = '';
this.state.values["data_type"] = ""; this.state.values.data_type = '';
this.state.values["experimenter"] = ""; this.state.values.experimenter = '';
this.state.values["publication_year"] = year; this.state.values.publication_year = year;
this.state.values["publication_month"] = month; this.state.values.publication_month = month;
this.state.values["publication_mday"] = mday; this.state.values.publication_mday = mday;
this.state.values["file.preview.caption"] = ""; this.state.values['file.preview.caption'] = '';
this.state.values["file.data_file.original_file_name"] = ""; this.state.values['file.data_file.original_file_name'] = '';
this.setIgnoreKey("publication_year"); this.setIgnoreKey('publication_year');
this.setIgnoreKey("publication_month"); this.setIgnoreKey('publication_month');
this.setIgnoreKey("publication_mday"); this.setIgnoreKey('publication_mday');
} }
getRows() { getRows() {
const rows = [ const rows = [
{ label: "[en]Title[/en][ja]タイトル[/ja]", value: this.renderFieldInputText("title", 50) }, { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) },
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: this.renderFieldInputText("keyword", 50) }, {
{ label: "[en]Description[/en][ja]概要[/ja]", value: this.renderFieldInputText("description", 50) }, label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
{ label: "ID", value: this.renderFieldInputText("doi", 50) }, value: this.renderFieldInputText('keyword', 50),
{ label: "[en]Data Type[/en][ja]データタイプ[/ja]", value: this.renderFieldSelect("data_type", ItemDataSubTypes) }, },
{ label: "[en]Experimenter[/en][ja]実験者[/ja]", value: this.renderFieldInputText("experimenter", 50) }, {
{ label: "[en]Date[/en][ja]日付[/ja]", value: this.renderFieldDate("", "publication_year", "publication_month", "publication_mday") }, label: '[en]Description[/en][ja]概要[/ja]',
{ label: "[en]Caption[/en][ja]キャプション[/ja]", value: this.renderFieldInputText("file.preview.caption", 50) }, value: this.renderFieldInputText('description', 50),
{ label: "[en]Data File[/en][ja]データファイル[/ja]", value: this.renderFieldInputText("file.data_file.original_file_name", 50) }, },
{ label: 'ID', value: this.renderFieldInputText('doi', 50) },
{
label: '[en]Data Type[/en][ja]データタイプ[/ja]',
value: this.renderFieldSelect('data_type', ItemDataSubTypes),
},
{
label: '[en]Experimenter[/en][ja]実験者[/ja]',
value: this.renderFieldInputText('experimenter', 50),
},
{
label: '[en]Date[/en][ja]日付[/ja]',
value: this.renderFieldDate(
'',
'publication_year',
'publication_month',
'publication_mday',
),
},
{
label: '[en]Caption[/en][ja]キャプション[/ja]',
value: this.renderFieldInputText('file.preview.caption', 50),
},
{
label: '[en]Data File[/en][ja]データファイル[/ja]',
value: this.renderFieldInputText('file.data_file.original_file_name', 50),
},
]; ];
return rows; return rows;
} }

View File

@ -1,39 +1,113 @@
import React from "react"; import Functions from '../../../functions';
import Functions from "../../../functions"; import ItemUtil, { ItemData } from '../../lib/ItemUtil';
import ItemUtil, { ItemData } from "../../lib/ItemUtil"; import DetailBase from '../lib/DetailBase';
import DetailBase from "../lib/DetailBase"; import ItemTypeField from '../lib/field';
import ItemTypeField from "../lib/field"; import SimPFLinkIcon from '../lib/field/SimPFLinkIcon';
import SimPFLinkIcon from "../lib/field/SimPFLinkIcon"; import DataUtil from './DataUtil';
import DataUtil from "./DataUtil";
class DataDetail extends DetailBase { class DataDetail extends DetailBase {
getFields() { getFields() {
const { lang, type } = this.props; const { lang, type } = this.props;
const item = this.props.item as ItemData; const item = this.props.item as ItemData;
const fields = [ const fields = [
{ label: "ID", value: item.doi }, { label: 'ID', value: item.doi },
{ label: "[en]Language[/en][ja]言語[/ja]", value: <ItemTypeField.Language lang={lang} itemLang={item.lang} /> }, {
{ label: "[en]Title[/en][ja]タイトル[/ja]", value: Functions.mlang(item.title, lang) }, label: '[en]Language[/en][ja]言語[/ja]',
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} /> }, value: <ItemTypeField.Language lang={lang} itemLang={item.lang} />,
{ label: "[en]Description[/en][ja]概要[/ja]", value: <ItemTypeField.Description lang={lang} description={item.description} /> }, },
{ label: "[en]Date[/en][ja]日付[/ja]", value: <ItemTypeField.PublicationDate lang={lang} year={item.publication_year} month={item.publication_month} mday={item.publication_mday} /> }, { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) },
{ label: "[en]Last Modified Date[/en][ja]最終更新日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} /> }, {
{ label: "[en]Created Date[/en][ja]作成日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} /> }, label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
{ label: "[en]Contributor[/en][ja]登録者[/ja]", value: <ItemTypeField.Contributer lang={lang} uname={item.uname} name={item.name} /> }, value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} />,
{ label: "[en]Item Type[/en][ja]アイテムタイプ[/ja]", value: item.item_type_display_name }, },
{ label: "[en]Change Log(History)[/en][ja]変更履歴[/ja]", value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} /> }, {
{ label: "[en]Data Type[/en][ja]データタイプ[/ja]", value: <DataUtil.DataType lang={lang} type={item.data_type} /> }, label: '[en]Description[/en][ja]概要[/ja]',
{ label: "[en]Experimenter[/en][ja]実験者[/ja]", value: <ItemTypeField.Author lang={lang} author={item.experimenter} /> }, value: <ItemTypeField.Description lang={lang} description={item.description} />,
{ label: "[en]Preview[/en][ja]プレビュー[/ja]", value: <ItemTypeField.Preview lang={lang} file={item.file} type={type} /> }, },
{ label: "[en]Data File[/en][ja]データファイル[/ja]", value: <ItemTypeField.ItemFile lang={lang} file={item.file} ftype="data_file" rights={item.rights} useCc={item.use_cc} ccCommercialUse={item.cc_commercial_use} ccModification={item.cc_modification} downloadLimit={item.attachment_dl_limit} type={type} /> }, {
{ label: "Readme", value: <ItemTypeField.Readme lang={lang} readme={item.readme} /> }, label: '[en]Date[/en][ja]日付[/ja]',
{ label: "Rights", value: <ItemTypeField.Rights lang={lang} rights={item.rights} useCc={item.use_cc} ccCommercialUse={item.cc_commercial_use} ccModification={item.cc_modification} /> }, value: (
{ label: "Index", value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} /> }, <ItemTypeField.PublicationDate
{ label: "[en]Related to[/en][ja]関連アイテム[/ja]", value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} /> }, lang={lang}
year={item.publication_year}
month={item.publication_month}
mday={item.publication_mday}
/>
),
},
{
label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} />,
},
{
label: '[en]Created Date[/en][ja]作成日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} />,
},
{
label: '[en]Contributor[/en][ja]登録者[/ja]',
value: <ItemTypeField.Contributor lang={lang} uname={item.uname} name={item.name} />,
},
{ label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name },
{
label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]',
value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} />,
},
{
label: '[en]Data Type[/en][ja]データタイプ[/ja]',
value: <DataUtil.DataType lang={lang} type={item.data_type} />,
},
{
label: '[en]Experimenter[/en][ja]実験者[/ja]',
value: <ItemTypeField.Author lang={lang} author={item.experimenter} />,
},
{
label: '[en]Preview[/en][ja]プレビュー[/ja]',
value: <ItemTypeField.Preview lang={lang} file={item.file} type={type} />,
},
{
label: '[en]Data File[/en][ja]データファイル[/ja]',
value: (
<ItemTypeField.ItemFile
lang={lang}
file={item.file}
fileType="data_file"
rights={item.rights}
useCc={item.use_cc}
ccCommercialUse={item.cc_commercial_use}
ccModification={item.cc_modification}
downloadLimit={item.attachment_dl_limit}
type={type}
/>
),
},
{ label: 'Readme', value: <ItemTypeField.Readme lang={lang} readme={item.readme} /> },
{
label: 'Rights',
value: (
<ItemTypeField.Rights
lang={lang}
rights={item.rights}
useCc={item.use_cc}
ccCommercialUse={item.cc_commercial_use}
ccModification={item.cc_modification}
/>
),
},
{
label: 'Index',
value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} />,
},
{
label: '[en]Related to[/en][ja]関連アイテム[/ja]',
value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} />,
},
]; ];
const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id); const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id);
if (simpfLinkUrl !== "") { if (simpfLinkUrl !== '') {
const field = { label: "Online Simulation", value: <SimPFLinkIcon lang={lang} url={simpfLinkUrl} isDetail={true} /> }; const field = {
label: 'Online Simulation',
value: <SimPFLinkIcon lang={lang} url={simpfLinkUrl} isDetail={true} />,
};
fields.splice(14, 0, field); fields.splice(14, 0, field);
} }
return fields; return fields;

View File

@ -1,14 +1,15 @@
import React, { Fragment } from "react"; import React from 'react';
import { Link } from "react-router-dom";
import Functions from "../../../functions"; import { Link } from 'react-router-dom';
import iconFile from "../../assets/images/icon_data.gif"; import Functions from '../../../functions';
import { ItemData } from "../../lib/ItemUtil"; import iconFile from '../../assets/images/icon_data.gif';
import ListBase, { ListBaseProps } from "../lib/ListBase"; import { ItemData } from '../../lib/ItemUtil';
import ListBase, { ListBaseProps } from '../lib/ListBase';
class DataList extends ListBase { class DataList extends ListBase {
constructor(props: ListBaseProps) { constructor(props: ListBaseProps) {
super(props); super(props);
this.label = "Data"; this.label = 'Data';
this.icon = iconFile; this.icon = iconFile;
} }
@ -17,10 +18,10 @@ class DataList extends ListBase {
const item = this.props.item as ItemData; const item = this.props.item as ItemData;
const authors = item.experimenter.map((author, i) => { const authors = item.experimenter.map((author, i) => {
return ( return (
<Fragment key={i}> <React.Fragment key={i}>
{i > 0 && ", "} {i > 0 && ', '}
{Functions.mlang(author, lang)} {Functions.mlang(author, lang)}
</Fragment> </React.Fragment>
); );
}); });
return ( return (

View File

@ -1,14 +1,15 @@
import iconFile from "../../assets/images/icon_data.gif"; import iconFile from '../../assets/images/icon_data.gif';
import { ItemDataSubTypes } from "../../lib/ItemUtil"; import { ItemDataSubTypes } from '../../lib/ItemUtil';
import TopBase, { TopBaseProps } from "../lib/TopBase"; import TopBase, { TopBaseProps } from '../lib/TopBase';
class DataTop extends TopBase { class DataTop extends TopBase {
constructor(props: TopBaseProps) { constructor(props: TopBaseProps) {
super(props); super(props);
this.type = "data"; this.type = 'data';
this.label = "Data"; this.label = 'Data';
this.icon = iconFile; this.icon = iconFile;
this.description = "[en]Result data in numerical text/image/movie formats.[/en][ja]実験結果の数値データ/画像/動画など[/ja]"; this.description =
'[en]Result data in numerical text/image/movie formats.[/en][ja]実験結果の数値データ/画像/動画など[/ja]';
this.subTypes = ItemDataSubTypes; this.subTypes = ItemDataSubTypes;
} }
} }

View File

@ -1,6 +1,6 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../config"; import { MultiLang } from '../../../config';
import { ItemDataSubType, ItemDataSubTypes } from "../../lib/ItemUtil"; import { ItemDataSubType, ItemDataSubTypes } from '../../lib/ItemUtil';
interface DataTypeProps { interface DataTypeProps {
lang: MultiLang; lang: MultiLang;
@ -12,7 +12,7 @@ const DataType: React.FC<DataTypeProps> = (props: DataTypeProps) => {
const subtype = ItemDataSubTypes.find((value) => { const subtype = ItemDataSubTypes.find((value) => {
return value.type === type; return value.type === type;
}); });
if (typeof subtype === "undefined") { if (typeof subtype === 'undefined') {
return null; return null;
} }
return <span>{subtype.label}</span>; return <span>{subtype.label}</span>;

View File

@ -1,7 +1,7 @@
import DataAdvancedSearch from "./DataAdvancedSearch"; import DataAdvancedSearch from './DataAdvancedSearch';
import DataDetail from "./DataDetail"; import DataDetail from './DataDetail';
import DataList from "./DataList"; import DataList from './DataList';
import DataTop from "./DataTop"; import DataTop from './DataTop';
const ItemTypeData = { const ItemTypeData = {
Top: DataTop, Top: DataTop,

View File

@ -1,26 +1,41 @@
import AdvancedSearchBase, { AdvancedSearchBaseProps } from "../lib/AdvancedSearchBase"; import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
class FilesAdvancedSearch extends AdvancedSearchBase { class FilesAdvancedSearch extends AdvancedSearchBase {
constructor(props: AdvancedSearchBaseProps) { constructor(props: AdvancedSearchBaseProps) {
super(props); super(props);
this.type = "files"; this.type = 'files';
this.title = "Files"; this.title = 'Files';
this.state.values["title"] = ""; this.state.values.title = '';
this.state.values["data_file_name"] = ""; this.state.values.data_file_name = '';
this.state.values["data_file_mimetype"] = ""; this.state.values.data_file_mimetype = '';
this.state.values["data_file_filetype"] = ""; this.state.values.data_file_filetype = '';
this.state.values["keyword"] = ""; this.state.values.keyword = '';
this.state.values["description"] = ""; this.state.values.description = '';
} }
getRows() { getRows() {
const rows = [ const rows = [
{ label: "[en]Title[/en][ja]タイトル[/ja]", value: this.renderFieldInputText("title", 50) }, { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) },
{ label: "- [en]File Name[/en][ja]ファイル名[/ja]", value: this.renderFieldInputText("data_file_name", 50) }, {
{ label: "- [en]MIME Type[/en][ja]MIMEタイプ[/ja]", value: this.renderFieldInputText("data_file_mimetype", 50) }, label: '- [en]File Name[/en][ja]ファイル名[/ja]',
{ label: "- [en]File Type[/en][ja]ファイルタイプ[/ja]", value: this.renderFieldInputText("data_file_filetype", 20) }, value: this.renderFieldInputText('data_file_name', 50),
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: this.renderFieldInputText("keyword", 50) }, },
{ label: "[en]Description[/en][ja]概要[/ja]", value: this.renderFieldInputText("description", 50) }, {
label: '- [en]MIME Type[/en][ja]MIMEタイプ[/ja]',
value: this.renderFieldInputText('data_file_mimetype', 50),
},
{
label: '- [en]File Type[/en][ja]ファイルタイプ[/ja]',
value: this.renderFieldInputText('data_file_filetype', 20),
},
{
label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
value: this.renderFieldInputText('keyword', 50),
},
{
label: '[en]Description[/en][ja]概要[/ja]',
value: this.renderFieldInputText('description', 50),
},
]; ];
return rows; return rows;
} }

View File

@ -1,30 +1,61 @@
import React from "react"; import Functions from '../../../functions';
import Functions from "../../../functions"; import { ItemFiles } from '../../lib/ItemUtil';
import { ItemFiles } from "../../lib/ItemUtil"; import DetailBase from '../lib/DetailBase';
import DetailBase from "../lib/DetailBase"; import ItemTypeField from '../lib/field';
import ItemTypeField from "../lib/field";
class FilesDetail extends DetailBase { class FilesDetail extends DetailBase {
getFields() { getFields() {
const { lang, type } = this.props; const { lang, type } = this.props;
const item = this.props.item as ItemFiles; const item = this.props.item as ItemFiles;
return [ return [
{ label: "ID", value: item.doi }, { label: 'ID', value: item.doi },
{ label: "[en]Language[/en][ja]言語[/ja]", value: <ItemTypeField.Language lang={lang} itemLang={item.lang} /> }, {
{ label: "[en]Title[/en][ja]タイトル[/ja]", value: Functions.mlang(item.title, lang) }, label: '[en]Language[/en][ja]言語[/ja]',
{ label: "[en]Last Modified Date[/en][ja]最終更新日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} /> }, value: <ItemTypeField.Language lang={lang} itemLang={item.lang} />,
{ label: "[en]Created Date[/en][ja]作成日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} /> }, },
{ label: "[en]Contributor[/en][ja]登録者[/ja]", value: <ItemTypeField.Contributer lang={lang} uname={item.uname} name={item.name} /> }, { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) },
{ label: "[en]Item Type[/en][ja]アイテムタイプ[/ja]", value: item.item_type_display_name }, {
{ label: "[en]Change Log(History)[/en][ja]変更履歴[/ja]", value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} /> }, label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]',
{ label: "[en]Data File[/en][ja]データファイル[/ja]", value: <ItemTypeField.ItemFile lang={lang} file={item.file} ftype="files_file" type={type} /> }, value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} />,
{ label: "- [en]File Name[/en][ja]ファイル名[/ja]", value: item.data_file_name }, },
{ label: "- [en]MIME Type[/en][ja]MIMEタイプ[/ja]", value: item.data_file_mimetype }, {
{ label: "- [en]File Type[/en][ja]ファイルタイプ[/ja]", value: item.data_file_filetype }, label: '[en]Created Date[/en][ja]作成日[/ja]',
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} /> }, value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} />,
{ label: "[en]Description[/en][ja]概要[/ja]", value: <ItemTypeField.Description lang={lang} description={item.description} /> }, },
{ label: "Index", value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} /> }, {
{ label: "[en]Related to[/en][ja]関連アイテム[/ja]", value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} /> }, label: '[en]Contributor[/en][ja]登録者[/ja]',
value: <ItemTypeField.Contributor lang={lang} uname={item.uname} name={item.name} />,
},
{ label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name },
{
label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]',
value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} />,
},
{
label: '[en]Data File[/en][ja]データファイル[/ja]',
value: (
<ItemTypeField.ItemFile lang={lang} file={item.file} fileType="files_file" type={type} />
),
},
{ label: '- [en]File Name[/en][ja]ファイル名[/ja]', value: item.data_file_name },
{ label: '- [en]MIME Type[/en][ja]MIMEタイプ[/ja]', value: item.data_file_mimetype },
{ label: '- [en]File Type[/en][ja]ファイルタイプ[/ja]', value: item.data_file_filetype },
{
label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} />,
},
{
label: '[en]Description[/en][ja]概要[/ja]',
value: <ItemTypeField.Description lang={lang} description={item.description} />,
},
{
label: 'Index',
value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} />,
},
{
label: '[en]Related to[/en][ja]関連アイテム[/ja]',
value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} />,
},
]; ];
} }
} }

View File

@ -1,15 +1,14 @@
import React from "react"; import { Link } from 'react-router-dom';
import { Link } from "react-router-dom"; import Functions from '../../../functions';
import Functions from "../../../functions"; import iconFile from '../../assets/images/icon_files.gif';
import iconFile from "../../assets/images/icon_files.gif"; import { ItemFiles } from '../../lib/ItemUtil';
import { ItemFiles } from "../../lib/ItemUtil"; import ListBase, { ListBaseProps } from '../lib/ListBase';
import Contributer from "../lib/field/Contributer"; import Contributor from '../lib/field/Contributor';
import ListBase, { ListBaseProps } from "../lib/ListBase";
class FilesList extends ListBase { class FilesList extends ListBase {
constructor(props: ListBaseProps) { constructor(props: ListBaseProps) {
super(props); super(props);
this.label = "Files"; this.label = 'Files';
this.icon = iconFile; this.icon = iconFile;
} }
@ -20,7 +19,7 @@ class FilesList extends ListBase {
<> <>
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link> <Link to={this.url}>{Functions.mlang(item.title, lang)}</Link>
<br /> <br />
<Contributer lang={lang} uname={item.uname} name={item.name} /> <Contributor lang={lang} uname={item.uname} name={item.name} />
<br /> <br />
{item.data_file_mimetype} {item.data_file_mimetype}
</> </>

View File

@ -1,14 +1,14 @@
import iconFile from "../../assets/images/icon_files.gif"; import iconFile from '../../assets/images/icon_files.gif';
import { ItemFilesSubTypes } from "../../lib/ItemUtil"; import { ItemFilesSubTypes } from '../../lib/ItemUtil';
import TopBase, { TopBaseProps } from "../lib/TopBase"; import TopBase, { TopBaseProps } from '../lib/TopBase';
class FilesTop extends TopBase { class FilesTop extends TopBase {
constructor(props: TopBaseProps) { constructor(props: TopBaseProps) {
super(props); super(props);
this.type = "files"; this.type = 'files';
this.label = "Files"; this.label = 'Files';
this.icon = iconFile; this.icon = iconFile;
this.description = "[en]Various type of File.[/en][ja]ファイル[/ja]"; this.description = '[en]Various type of File.[/en][ja]ファイル[/ja]';
this.subTypes = ItemFilesSubTypes; this.subTypes = ItemFilesSubTypes;
} }
} }

View File

@ -1,7 +1,7 @@
import FilesAdvancedSearch from "./FilesAdvancedSearch"; import FilesAdvancedSearch from './FilesAdvancedSearch';
import FilesDetail from "./FilesDetail"; import FilesDetail from './FilesDetail';
import FilesList from "./FilesList"; import FilesList from './FilesList';
import FilesTop from "./FilesTop"; import FilesTop from './FilesTop';
const ItemTypeFiles = { const ItemTypeFiles = {
Top: FilesTop, Top: FilesTop,

View File

@ -1,7 +1,21 @@
import React from 'react'; import { BrainAtlasType, MultiLang } from '../../config';
import { MultiLang, BrainAtlasType } from '../../config';
import AdvancedSearchQuery from '../lib/AdvancedSearchQuery'; import AdvancedSearchQuery from '../lib/AdvancedSearchQuery';
import { Item, ItemBinder, ItemBook, ItemConference, ItemData, ItemFiles, ItemModel, ItemPaper, ItemPresentation, ItemSimulator, ItemStimulus, ItemTool, ItemUrl, ItemMemo } from '../lib/ItemUtil'; import {
Item,
ItemBinder,
ItemBook,
ItemConference,
ItemData,
ItemFiles,
ItemMemo,
ItemModel,
ItemPaper,
ItemPresentation,
ItemSimulator,
ItemStimulus,
ItemTool,
ItemUrl,
} from '../lib/ItemUtil';
import ItemTypeBinder from './binder'; import ItemTypeBinder from './binder';
import ItemTypeBook from './book'; import ItemTypeBook from './book';
import ItemTypeConference from './conference'; import ItemTypeConference from './conference';
@ -53,7 +67,7 @@ const Top = (props: TopProps) => {
default: default:
return null; return null;
} }
} };
interface ListProps { interface ListProps {
lang: MultiLang; lang: MultiLang;
@ -92,7 +106,7 @@ const List = (props: ListProps) => {
default: default:
return null; return null;
} }
} };
interface DetailProps { interface DetailProps {
lang: MultiLang; lang: MultiLang;
@ -119,7 +133,9 @@ const Detail = (props: DetailProps) => {
case 'xnppaper': case 'xnppaper':
return <ItemTypePaper.Detail lang={lang} item={item as ItemPaper} type={type} />; return <ItemTypePaper.Detail lang={lang} item={item as ItemPaper} type={type} />;
case 'xnppresentation': case 'xnppresentation':
return <ItemTypePresentation.Detail lang={lang} item={item as ItemPresentation} type={type} />; return (
<ItemTypePresentation.Detail lang={lang} item={item as ItemPresentation} type={type} />
);
case 'xnpsimulator': case 'xnpsimulator':
return <ItemTypeSimulator.Detail lang={lang} item={item as ItemSimulator} type={type} />; return <ItemTypeSimulator.Detail lang={lang} item={item as ItemSimulator} type={type} />;
case 'xnpstimulus': case 'xnpstimulus':
@ -131,7 +147,7 @@ const Detail = (props: DetailProps) => {
default: default:
return null; return null;
} }
} };
interface AdvancedSearchProps { interface AdvancedSearchProps {
lang: MultiLang; lang: MultiLang;
@ -170,13 +186,13 @@ const AdvancedSearch = (props: AdvancedSearchProps) => {
default: default:
return null; return null;
} }
} };
const ItemType = { const ItemType = {
Top, Top,
List, List,
Detail, Detail,
AdvancedSearch AdvancedSearch,
} };
export default ItemType; export default ItemType;

View File

@ -1,8 +1,8 @@
import React, { ChangeEvent } from "react"; import React from 'react';
import { MultiLang } from "../../../config"; import { MultiLang } from '../../../config';
import Functions from "../../../functions"; import Functions from '../../../functions';
import AdvancedSearchQuery from "../../lib/AdvancedSearchQuery"; import AdvancedSearchQuery from '../../lib/AdvancedSearchQuery';
import { ItemSubTypes } from "../../lib/ItemUtil"; import { ItemSubTypesAll } from '../../lib/ItemUtil';
export interface AdvancedSearchBaseProps { export interface AdvancedSearchBaseProps {
lang: MultiLang; lang: MultiLang;
@ -11,12 +11,12 @@ export interface AdvancedSearchBaseProps {
interface State { interface State {
show: boolean; show: boolean;
values: any; values: Record<string, string>;
} }
class AdvancedSearchBase extends React.Component<AdvancedSearchBaseProps, State> { class AdvancedSearchBase extends React.Component<AdvancedSearchBaseProps, State> {
protected type: string = "base"; protected type = 'base';
protected title: string = "Base"; protected title = 'Base';
protected query: AdvancedSearchQuery; protected query: AdvancedSearchQuery;
protected ignoreKeys: string[] = []; protected ignoreKeys: string[] = [];
@ -55,13 +55,13 @@ class AdvancedSearchBase extends React.Component<AdvancedSearchBaseProps, State>
} }
updateField(key: string, value: string) { updateField(key: string, value: string) {
let values = Object.assign({}, this.state.values); const values = Object.assign({}, this.state.values);
values[key] = value; values[key] = value;
this.updateQuery(key, value); this.updateQuery(key, value);
this.setState({ values }); this.setState({ values });
} }
handleChangeTitleCheck(e: ChangeEvent<HTMLInputElement>) { handleChangeTitleCheck(e: React.ChangeEvent<HTMLInputElement>) {
const show = e.target.checked; const show = e.target.checked;
if (show) { if (show) {
Object.keys(this.state.values).forEach((key) => { Object.keys(this.state.values).forEach((key) => {
@ -79,14 +79,22 @@ class AdvancedSearchBase extends React.Component<AdvancedSearchBaseProps, State>
} }
renderFieldInputText(key: string, size: number) { renderFieldInputText(key: string, size: number) {
const onChange = (e: ChangeEvent<HTMLInputElement>) => { const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
this.updateField(key, e.target.value); this.updateField(key, e.target.value);
}; };
return <input className="fieldInputText" type="text" value={this.state.values[key]} size={size} onChange={onChange} />; return (
<input
className="fieldInputText"
type="text"
value={this.state.values[key]}
size={size}
onChange={onChange}
/>
);
} }
renderFieldSelect(key: string, values: ItemSubTypes<any>) { renderFieldSelect(key: string, values: ItemSubTypesAll) {
const onChange = (e: ChangeEvent<HTMLSelectElement>) => { const onChange: React.ChangeEventHandler<HTMLSelectElement> = (e) => {
this.updateField(key, e.target.value); this.updateField(key, e.target.value);
}; };
const options = values.map(({ type, label }, i) => { const options = values.map(({ type, label }, i) => {
@ -105,18 +113,31 @@ class AdvancedSearchBase extends React.Component<AdvancedSearchBaseProps, State>
} }
renderFieldDate(label: string, keyYear: string, keyMonth: string, keyMday: string) { renderFieldDate(label: string, keyYear: string, keyMonth: string, keyMday: string) {
const onChange = (e: ChangeEvent<HTMLInputElement>) => { const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
if (e.target.checked) { if (e.target.checked) {
this.deleteIgnoreKey(keyYear); this.deleteIgnoreKey(keyYear);
keyMonth !== "" && this.deleteIgnoreKey(keyMonth); keyMonth !== '' && this.deleteIgnoreKey(keyMonth);
keyMday !== "" && this.deleteIgnoreKey(keyMday); keyMday !== '' && this.deleteIgnoreKey(keyMday);
} else { } else {
this.setIgnoreKey(keyYear); this.setIgnoreKey(keyYear);
keyMonth !== "" && this.setIgnoreKey(keyMonth); keyMonth !== '' && this.setIgnoreKey(keyMonth);
keyMday !== "" && this.setIgnoreKey(keyMday); keyMday !== '' && this.setIgnoreKey(keyMday);
} }
}; };
const month = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; const month = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
const monthOptions = month.map((value, i) => { const monthOptions = month.map((value, i) => {
return ( return (
<option key={i} value={i + 1}> <option key={i} value={i + 1}>
@ -124,29 +145,40 @@ class AdvancedSearchBase extends React.Component<AdvancedSearchBaseProps, State>
</option> </option>
); );
}); });
let mdayOptions: JSX.Element[] = []; const mdayOptions: JSX.Element[] = [];
for (let i = 1; i <= 31; i++) { for (let i = 1; i <= 31; i++) {
mdayOptions.push( mdayOptions.push(
<option key={i} value={i}> <option key={i} value={i}>
{i} {i}
</option> </option>,
); );
} }
return ( return (
<div className="fieldDate"> <div className="fieldDate">
<input type="checkbox" onChange={onChange} /> <input type="checkbox" onChange={onChange} />
{label.length !== 0 && <label className="fieldDateLabel">{label}</label>} {label.length !== 0 && <label className="fieldDateLabel">{label}</label>}
{keyMonth !== "" && ( {keyMonth !== '' && (
<select value={this.state.values[keyMonth]} onChange={(e) => this.updateField(keyMonth, e.target.value)}> <select
value={this.state.values[keyMonth]}
onChange={(e) => this.updateField(keyMonth, e.target.value)}
>
{monthOptions} {monthOptions}
</select> </select>
)} )}
{keyMday !== "" && ( {keyMday !== '' && (
<select value={this.state.values[keyMday]} onChange={(e) => this.updateField(keyMday, e.target.value)}> <select
value={this.state.values[keyMday]}
onChange={(e) => this.updateField(keyMday, e.target.value)}
>
{mdayOptions} {mdayOptions}
</select> </select>
)} )}
<input type="text" value={this.state.values[keyYear]} size={5} onChange={(e) => this.updateField(keyYear, e.target.value)} /> <input
type="text"
value={this.state.values[keyYear]}
size={5}
onChange={(e) => this.updateField(keyYear, e.target.value)}
/>
</div> </div>
); );
} }
@ -158,7 +190,7 @@ class AdvancedSearchBase extends React.Component<AdvancedSearchBaseProps, State>
} }
const rows = this.getRows(); const rows = this.getRows();
const fields = rows.map((value, idx) => { const fields = rows.map((value, idx) => {
const evenodd = idx % 2 === 0 ? "even" : "odd"; const evenodd = idx % 2 === 0 ? 'even' : 'odd';
return ( return (
<tr key={idx}> <tr key={idx}>
<td className="head">{Functions.mlang(value.label, lang)}</td> <td className="head">{Functions.mlang(value.label, lang)}</td>
@ -180,7 +212,11 @@ class AdvancedSearchBase extends React.Component<AdvancedSearchBaseProps, State>
<tbody> <tbody>
<tr> <tr>
<th align="left"> <th align="left">
<input type="checkbox" checked={this.state.show} onChange={this.handleChangeTitleCheck} /> <input
type="checkbox"
checked={this.state.show}
onChange={(e) => this.handleChangeTitleCheck(e)}
/>
{this.title} {this.title}
</th> </th>
</tr> </tr>

View File

@ -1,11 +1,12 @@
import React, { ReactNode } from "react"; import React from 'react';
import { BrainAtlasType, MultiLang } from "../../../config";
import Functions from "../../../functions"; import { BrainAtlasType, MultiLang } from '../../../config';
import { Item } from "../../lib/ItemUtil"; import Functions from '../../../functions';
import { Item } from '../../lib/ItemUtil';
export interface DetailBaseField { export interface DetailBaseField {
label: string; label: string;
value: ReactNode; value: React.ReactNode;
} }
export interface DetailBaseProps { export interface DetailBaseProps {
@ -22,7 +23,7 @@ class DetailBase extends React.Component<DetailBaseProps> {
render() { render() {
const { lang } = this.props; const { lang } = this.props;
const elements = this.getFields().map((value, idx) => { const elements = this.getFields().map((value, idx) => {
const evenodd = idx % 2 === 0 ? "even" : "odd"; const evenodd = idx % 2 === 0 ? 'even' : 'odd';
return ( return (
<tr key={idx}> <tr key={idx}>
<td className="head">{Functions.mlang(value.label, lang)}</td> <td className="head">{Functions.mlang(value.label, lang)}</td>

View File

@ -1,7 +1,8 @@
import React from "react"; import React from 'react';
import { BrainAtlasType, MultiLang } from "../../../config";
import ItemUtil, { Item } from "../../lib/ItemUtil"; import { BrainAtlasType, MultiLang } from '../../../config';
import SimPFLinkIcon from "./field/SimPFLinkIcon"; import ItemUtil, { Item } from '../../lib/ItemUtil';
import SimPFLinkIcon from './field/SimPFLinkIcon';
export interface ListBaseProps { export interface ListBaseProps {
lang: MultiLang; lang: MultiLang;
@ -10,8 +11,8 @@ export interface ListBaseProps {
} }
class ListBase extends React.Component<ListBaseProps> { class ListBase extends React.Component<ListBaseProps> {
protected label = ""; protected label = '';
protected icon = ""; protected icon = '';
protected url: string; protected url: string;
protected simpfLinkUrl: string; protected simpfLinkUrl: string;

View File

@ -1,8 +1,9 @@
import React, { Fragment } from "react"; import React from 'react';
import { Link } from "react-router-dom";
import { BrainAtlasType, MultiLang } from "../../../config"; import { Link } from 'react-router-dom';
import Functions from "../../../functions"; import { BrainAtlasType, MultiLang } from '../../../config';
import ItemUtil, { ItemSubTypes } from "../../lib/ItemUtil"; import Functions from '../../../functions';
import ItemUtil, { ItemSubTypesAll } from '../../lib/ItemUtil';
export interface TopBaseProps { export interface TopBaseProps {
lang: MultiLang; lang: MultiLang;
@ -10,22 +11,22 @@ export interface TopBaseProps {
} }
class TopBase extends React.Component<TopBaseProps> { class TopBase extends React.Component<TopBaseProps> {
protected type: string = ""; protected type = '';
protected label: string = ""; protected label = '';
protected icon: string = ""; protected icon = '';
protected description: string = ""; protected description = '';
protected subTypes: ItemSubTypes<any> = []; protected subTypes: ItemSubTypesAll = [];
render() { render() {
const { lang, type } = this.props; const { lang, type } = this.props;
const url = ItemUtil.getItemTypeSearchUrl(type, this.type, ""); const url = ItemUtil.getItemTypeSearchUrl(type, this.type, '');
const links = this.subTypes.map((subtype, i) => { const links = this.subTypes.map((subtype, i) => {
const url = ItemUtil.getItemTypeSearchUrl(type, this.type, subtype.type); const url = ItemUtil.getItemTypeSearchUrl(type, this.type, subtype.type);
return ( return (
<Fragment key={i}> <React.Fragment key={i}>
{i > 0 && " / "} {i > 0 && ' / '}
<Link to={url}>{subtype.label}</Link> <Link to={url}>{subtype.label}</Link>
</Fragment> </React.Fragment>
); );
}); });
return ( return (

View File

@ -1,18 +1,19 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config";
import { MultiLang } from '../../../../config';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
author: string[]; author: string[];
} }
const Author: React.FC<Props> = (props: Props) => { const Author: React.FC<Props> = (props) => {
const { author } = props; const { author } = props;
if (author.length === 0) { if (author.length === 0) {
return null; return null;
} }
const elements = author.map((value, idx) => { const elements = author.map((value, idx) => {
const evenodd = idx % 2 === 0 ? "even" : "odd"; const evenodd = idx % 2 === 0 ? 'even' : 'odd';
return ( return (
<tr key={idx}> <tr key={idx}>
<td className={evenodd}>{value}</td> <td className={evenodd}>{value}</td>

View File

@ -1,15 +1,16 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config";
import Functions from "../../../../functions"; import { MultiLang } from '../../../../config';
import { ItemBasicChangeLog } from "../../../lib/ItemUtil"; import Functions from '../../../../functions';
import DateTime from "./DateTime"; import { ItemBasicChangeLog } from '../../../lib/ItemUtil';
import DateTime from './DateTime';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
changelog: ItemBasicChangeLog[]; changelog: ItemBasicChangeLog[];
} }
const ChangeLog: React.FC<Props> = (props: Props) => { const ChangeLog: React.FC<Props> = (props) => {
const { lang, changelog } = props; const { lang, changelog } = props;
if (changelog.length === 0) { if (changelog.length === 0) {
return null; return null;

View File

@ -1,18 +0,0 @@
import React from "react";
import { MultiLang } from "../../../../config";
import Functions from "../../../../functions";
interface Props {
lang: MultiLang;
uname: string;
name: string;
}
const Contributer: React.FC<Props> = (props: Props) => {
const { lang, name, uname } = props;
const unsubscribed = "([en]Unsubscribed User[/en][ja]退会済みユーザ[/ja])";
const label = uname === "" ? unsubscribed : name === "" ? uname : name + " (" + uname + ")";
return <span>{Functions.mlang(label, lang)}</span>;
};
export default Contributer;

View File

@ -0,0 +1,19 @@
import React from 'react';
import { MultiLang } from '../../../../config';
import Functions from '../../../../functions';
interface Props {
lang: MultiLang;
uname: string;
name: string;
}
const Contributor: React.FC<Props> = (props) => {
const { lang, name, uname } = props;
const unsubscribed = '([en]Unsubscribed User[/en][ja]退会済みユーザ[/ja])';
const label = uname === '' ? unsubscribed : name === '' ? uname : name + ' (' + uname + ')';
return <span>{Functions.mlang(label, lang)}</span>;
};
export default Contributor;

View File

@ -1,51 +1,57 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config";
export type CreativeCommonsType = "by" | "by-nc" | "by-nc-nd" | "by-nc-sa" | "by-nd" | "by-sa"; import { MultiLang } from '../../../../config';
export const getCreativeCommonsType = (ccCommercialUse: number, ccModification: number): CreativeCommonsType => { type CreativeCommonsType = 'by' | 'by-nc' | 'by-nc-nd' | 'by-nc-sa' | 'by-nd' | 'by-sa';
const getCreativeCommonsType = (
ccCommercialUse: number,
ccModification: number,
): CreativeCommonsType => {
const cc = ccCommercialUse * 10 + ccModification; const cc = ccCommercialUse * 10 + ccModification;
switch (cc) { switch (cc) {
case 0: case 0:
return "by-nc-nd"; return 'by-nc-nd';
case 1: case 1:
return "by-nc-sa"; return 'by-nc-sa';
case 2: case 2:
return "by-nc"; return 'by-nc';
case 10: case 10:
return "by-nd"; return 'by-nd';
case 11: case 11:
return "by-sa"; return 'by-sa';
case 12: case 12:
default: default:
return "by"; return 'by';
} }
}; };
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
type: CreativeCommonsType; ccCommercialUse: number;
ccModification: number;
} }
const CreativeCommons: React.FC<Props> = (props: Props) => { const CreativeCommons: React.FC<Props> = (props) => {
const { type } = props; const { ccCommercialUse, ccModification } = props;
const url = "http://creativecommons.org/licenses/" + type + "/4.0/"; const type = getCreativeCommonsType(ccCommercialUse, ccModification);
const logoUrl = "https://i.creativecommons.org/l/" + type + "/4.0/88x31.png"; const url = 'http://creativecommons.org/licenses/' + type + '/4.0/';
const logoUrl = 'https://i.creativecommons.org/l/' + type + '/4.0/88x31.png';
const labels = { const labels = {
by: "Attribution", by: 'Attribution',
nc: "NonCommercial", nc: 'NonCommercial',
nd: "NoDerivatives", nd: 'NoDerivatives',
sa: "ShareAlike", sa: 'ShareAlike',
}; };
const label = type const label = type
.split("-") .split('-')
.map((value) => { .map((value) => {
const prop = value as "by" | "nc" | "nd" | "sa"; const prop = value as 'by' | 'nc' | 'nd' | 'sa';
return labels[prop]; return labels[prop];
}) })
.join("-"); .join('-');
return ( return (
<table style={{ borderCollapse: "separate", borderSpacing: "5px" }}> <table style={{ borderCollapse: 'separate', borderSpacing: '5px' }}>
<tbody> <tbody>
<tr> <tr>
<td> <td>
@ -54,9 +60,9 @@ const CreativeCommons: React.FC<Props> = (props: Props) => {
</a> </a>
</td> </td>
<td> <td>
This work is licensed under a{" "} This work is licensed under a{' '}
<a href={url} target="_blank" rel="license noopener noreferrer"> <a href={url} target="_blank" rel="license noopener noreferrer">
Criative Commons {label} 4.0 International License Creative Commons {label} 4.0 International License
</a> </a>
. .
</td> </td>

View File

@ -1,6 +1,7 @@
import moment from "moment"; import React from 'react';
import React from "react";
import { MultiLang } from "../../../../config"; import moment from 'moment';
import { MultiLang } from '../../../../config';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -8,12 +9,12 @@ interface Props {
onlyDate?: boolean; onlyDate?: boolean;
} }
const DateTime: React.FC<Props> = (props: Props) => { const DateTime: React.FC<Props> = (props) => {
const { date, onlyDate } = props; const { date, onlyDate } = props;
const d = moment(new Date(date * 1000)); const d = moment(new Date(date * 1000));
let format = "MMM D, Y"; let format = 'MMM D, Y';
if (typeof onlyDate === "undefined" || !onlyDate) { if (typeof onlyDate === 'undefined' || !onlyDate) {
format += " HH:mm:ss"; format += ' HH:mm:ss';
} }
return <span>{d.format(format)}</span>; return <span>{d.format(format)}</span>;
}; };

View File

@ -1,6 +1,7 @@
import React from "react"; import React from 'react';
import XoopsCode from "../../../../common/lib/XoopsCode";
import { MultiLang } from "../../../../config"; import XoopsCode from '../../../../common/lib/XoopsCode';
import { MultiLang } from '../../../../config';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -8,10 +9,10 @@ interface Props {
className?: string; className?: string;
} }
const Description: React.FC<Props> = (props: Props) => { const Description: React.FC<Props> = (props) => {
const { lang, description, className } = props; const { lang, description, className } = props;
const textarea = <XoopsCode lang={lang} text={description} dobr={true} />; const textarea = <XoopsCode lang={lang} text={description} dobr={true} />;
const name = typeof className === "undefined" ? "description" : className; const name = typeof className === 'undefined' ? 'description' : className;
return <div className={name}>{textarea}</div>; return <div className={name}>{textarea}</div>;
}; };

View File

@ -1,8 +1,9 @@
import React from "react"; import React from 'react';
import { BrainAtlasType, MultiLang } from "../../../../config";
import ItemUtil, { ItemBasicFile } from "../../../lib/ItemUtil"; import { BrainAtlasType, MultiLang } from '../../../../config';
import styles from "./FileDownloadButton.module.css"; import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil';
import LicenseAgreementDialog from "./LicenseAgreementDialog"; import styles from './FileDownloadButton.module.css';
import LicenseAgreementDialog from './LicenseAgreementDialog';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -14,44 +15,45 @@ interface Props {
type: BrainAtlasType; type: BrainAtlasType;
} }
interface State { const FileDownloadButton: React.FC<Props> = (props) => {
show: boolean; const { lang, file, rights, useCc, ccCommercialUse, ccModification, type } = props;
}
class FileDownloadButton extends React.Component<Props, State> { const [show, setShow] = React.useState<boolean>(false);
constructor(props: Props) {
super(props);
this.state = {
show: false,
};
this.handleClickDownload = this.handleClickDownload.bind(this);
this.unsetShow = this.unsetShow.bind(this);
}
handleClickDownload(e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) { const handleClickDownload: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
if (this.props.rights !== "") { if (rights !== '') {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
this.setState({ show: true }); setShow(true);
}
} }
};
unsetShow() { const url = ItemUtil.getFileUrl(type, file);
this.setState({ show: false });
}
render() {
const { lang, file, rights, useCc, ccCommercialUse, ccModification, type } = this.props;
const url = ItemUtil.getFileUrl(type, this.props.file);
return ( return (
<> <>
<a className={styles.downloadButton} href={url} download={file.original_file_name} target="_blank" rel="noopener noreferrer" onClick={this.handleClickDownload}> <a
className={styles.downloadButton}
href={url}
download={file.original_file_name}
target="_blank"
rel="noopener noreferrer"
onClick={handleClickDownload}
>
Download Download
</a> </a>
<LicenseAgreementDialog lang={lang} file={file} rights={rights} useCc={useCc} ccCommercialUse={ccCommercialUse} ccModification={ccModification} show={this.state.show} unsetShow={this.unsetShow} type={type} /> <LicenseAgreementDialog
lang={lang}
file={file}
rights={rights}
useCc={useCc}
ccCommercialUse={ccCommercialUse}
ccModification={ccModification}
show={show}
unsetShow={() => setShow(false)}
type={type}
/>
</> </>
); );
} };
}
export default FileDownloadButton; export default FileDownloadButton;

View File

@ -1,16 +1,17 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config";
import { MultiLang } from '../../../../config';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
size: number; size: number;
} }
const FileSize: React.FC<Props> = (props: Props) => { const FileSize: React.FC<Props> = (props) => {
const { size } = props; const { size } = props;
const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const power = size > 0 ? Math.floor(Math.log(size) / Math.log(1024)) : 0; const power = size > 0 ? Math.floor(Math.log(size) / Math.log(1024)) : 0;
const label = Math.round((size / Math.pow(1024, power)) * 10) / 10 + " " + units[power]; const label = Math.round((size / Math.pow(1024, power)) * 10) / 10 + ' ' + units[power];
return <span>{label}</span>; return <span>{label}</span>;
}; };

View File

@ -1,17 +1,18 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config";
import { MultiLang } from '../../../../config';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
keyword: string[]; keyword: string[];
} }
const FreeKeyword: React.FC<Props> = (props: Props) => { const FreeKeyword: React.FC<Props> = (props) => {
const { keyword } = props; const { keyword } = props;
if (keyword.length === 0) { if (keyword.length === 0) {
return null; return null;
} }
const label = keyword.join(", "); const label = keyword.join(', ');
return <span>{label}</span>; return <span>{label}</span>;
}; };

View File

@ -1,15 +1,16 @@
import React from "react"; import React from 'react';
import { BrainAtlasType, MultiLang } from "../../../../config";
import Functions from "../../../../functions"; import { BrainAtlasType, MultiLang } from '../../../../config';
import { ItemBasicFile } from "../../../lib/ItemUtil"; import Functions from '../../../../functions';
import DateTime from "./DateTime"; import { ItemBasicFile } from '../../../lib/ItemUtil';
import FileDownloadButton from "./FileDownloadButton"; import DateTime from './DateTime';
import FileSize from "./FileSize"; import FileDownloadButton from './FileDownloadButton';
import FileSize from './FileSize';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
file: ItemBasicFile[]; file: ItemBasicFile[];
ftype: string; fileType: string;
rights?: string; rights?: string;
useCc?: number; useCc?: number;
ccCommercialUse?: number; ccCommercialUse?: number;
@ -18,17 +19,24 @@ interface Props {
type: BrainAtlasType; type: BrainAtlasType;
} }
const ItemFile: React.FC<Props> = (props: Props) => { const ItemFile: React.FC<Props> = (props) => {
const { lang, file, ftype, type } = props; const {
const rights = typeof props.rights === "undefined" ? "" : props.rights; lang,
const useCc = typeof props.useCc === "undefined" ? 0 : props.useCc; file,
const ccCommercialUse = typeof props.ccCommercialUse === "undefined" ? 0 : props.ccCommercialUse; fileType,
const ccModification = typeof props.ccModification === "undefined" ? 0 : props.ccModification; type,
const downloadLimit = typeof props.downloadLimit === "undefined" ? 0 : props.downloadLimit; rights = '',
useCc = 0,
ccCommercialUse = 0,
ccModification = 0,
downloadLimit = 0,
} = props;
const data = file.find((value) => { const data = file.find((value) => {
return value.file_type_name === ftype; return value.file_type_name === fileType;
}); });
if (typeof data === "undefined") {
if (typeof data === 'undefined') {
return null; return null;
} }
const date = new Date(data.timestamp); const date = new Date(data.timestamp);
@ -42,7 +50,19 @@ const ItemFile: React.FC<Props> = (props: Props) => {
<tr> <tr>
<td>Type</td> <td>Type</td>
<td>: {data.mime_type}</td> <td>: {data.mime_type}</td>
<td rowSpan={4}>{downloadLimit === 0 && <FileDownloadButton lang={lang} file={data} rights={rights} useCc={useCc} ccCommercialUse={ccCommercialUse} ccModification={ccModification} type={type} />}</td> <td rowSpan={4}>
{downloadLimit === 0 && (
<FileDownloadButton
lang={lang}
file={data}
rights={rights}
useCc={useCc}
ccCommercialUse={ccCommercialUse}
ccModification={ccModification}
type={type}
/>
)}
</td>
</tr> </tr>
<tr> <tr>
<td>Size</td> <td>Size</td>
@ -60,7 +80,9 @@ const ItemFile: React.FC<Props> = (props: Props) => {
</table> </table>
{downloadLimit === 1 && ( {downloadLimit === 1 && (
<> <>
<br />({Functions.mlang("[en]File has been removed[/en][ja]ファイルは削除されました[/ja]", lang)}) <br />(
{Functions.mlang('[en]File has been removed[/en][ja]ファイルは削除されました[/ja]', lang)}
)
</> </>
)} )}
</div> </div>

View File

@ -1,9 +1,10 @@
import React from "react"; import React from 'react';
import { Link } from "react-router-dom";
import { BrainAtlasType, MultiLang } from "../../../../config"; import { Link } from 'react-router-dom';
import Functions from "../../../../functions"; import { BrainAtlasType, MultiLang } from '../../../../config';
import IndexUtil from "../../../lib/IndexUtil"; import Functions from '../../../../functions';
import { ItemBasicIndex } from "../../../lib/ItemUtil"; import IndexUtil from '../../../lib/IndexUtil';
import { ItemBasicIndex } from '../../../lib/ItemUtil';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -11,13 +12,13 @@ interface Props {
type: BrainAtlasType; type: BrainAtlasType;
} }
const ItemIndex: React.FC<Props> = (props: Props) => { const ItemIndex: React.FC<Props> = (props) => {
const { lang, index, type } = props; const { lang, index, type } = props;
if (index.length === 0) { if (index.length === 0) {
return null; return null;
} }
const elements = index.map((value, idx) => { const elements = index.map((value, idx) => {
const evenodd = idx % 2 === 0 ? "even" : "odd"; const evenodd = idx % 2 === 0 ? 'even' : 'odd';
const url = IndexUtil.getUrl(type, value.index_id); const url = IndexUtil.getUrl(type, value.index_id);
return ( return (
<tr key={value.index_id}> <tr key={value.index_id}>

View File

@ -1,30 +1,30 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config"; import { MultiLang } from '../../../../config';
import Functions from "../../../../functions"; import Functions from '../../../../functions';
import { ItemBasicLang } from "../../../lib/ItemUtil"; import { ItemBasicLang } from '../../../lib/ItemUtil';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
itemLang: ItemBasicLang; itemLang: ItemBasicLang;
} }
const Language: React.FC<Props> = (props: Props) => { const Language: React.FC<Props> = (props) => {
const { lang, itemLang } = props; const { lang, itemLang } = props;
const langStr = { const langStr = {
eng: "[en]English[/en][ja]英語[/ja]", eng: '[en]English[/en][ja]英語[/ja]',
jpn: "[en]Japanese[/en][ja]日本語[/ja]", jpn: '[en]Japanese[/en][ja]日本語[/ja]',
fra: "[en]French[/en][ja]フランス語[/ja]", fra: '[en]French[/en][ja]フランス語[/ja]',
deu: "[en]German[/en][ja]ドイツ語[/ja]", deu: '[en]German[/en][ja]ドイツ語[/ja]',
esl: "[en]Spanish[/en][ja]スペイン語[/ja]", esl: '[en]Spanish[/en][ja]スペイン語[/ja]',
ita: "[en]Italian[/en][ja]イタリア語[/ja]", ita: '[en]Italian[/en][ja]イタリア語[/ja]',
dut: "[en]Dutch[/en][ja]オランダ語[/ja]", dut: '[en]Dutch[/en][ja]オランダ語[/ja]',
sve: "[en]Swedish[/en][ja]スウェーデン語[/ja]", sve: '[en]Swedish[/en][ja]スウェーデン語[/ja]',
nor: "[en]Norwegian[/en][ja]ノルウェー語[/ja]", nor: '[en]Norwegian[/en][ja]ノルウェー語[/ja]',
dan: "[en]Danish[/en][ja]デンマーク語[/ja]", dan: '[en]Danish[/en][ja]デンマーク語[/ja]',
fin: "[en]Finnish[/en][ja]フィンランド語[/ja]", fin: '[en]Finnish[/en][ja]フィンランド語[/ja]',
por: "[en]Portuguese[/en][ja]ポルトガル語[/ja]", por: '[en]Portuguese[/en][ja]ポルトガル語[/ja]',
chi: "[en]Chinese[/en][ja]中国語[/ja]", chi: '[en]Chinese[/en][ja]中国語[/ja]',
kor: "[en]Korean[/en][ja]韓国語[/ja]", kor: '[en]Korean[/en][ja]韓国語[/ja]',
}; };
if (!(itemLang in langStr)) { if (!(itemLang in langStr)) {
return null; return null;

View File

@ -1,12 +1,14 @@
import React, { ChangeEvent, MouseEvent } from "react"; import React from 'react';
import { Modal } from "react-overlays";
import { BrainAtlasType, MultiLang } from "../../../../config"; import { Modal } from 'react-overlays';
import Functions from "../../../../functions"; import { RenderModalBackdropProps } from 'react-overlays/cjs/Modal';
import ItemUtil, { ItemBasicFile } from "../../../lib/ItemUtil"; import { BrainAtlasType, MultiLang } from '../../../../config';
import DateTime from "./DateTime"; import Functions from '../../../../functions';
import FileSize from "./FileSize"; import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil';
import styles from "./LicenseAgreementDialog.module.css"; import DateTime from './DateTime';
import Rights from "./Rights"; import FileSize from './FileSize';
import styles from './LicenseAgreementDialog.module.css';
import Rights from './Rights';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -20,72 +22,67 @@ interface Props {
type: BrainAtlasType; type: BrainAtlasType;
} }
interface State { const LicenseAgreementDialog: React.FC<Props> = (props) => {
show: boolean; const { lang, file, rights, useCc, ccCommercialUse, ccModification, show, unsetShow, type } =
disabled: boolean; props;
}
class LicenseAgreementDialog extends React.Component<Props, State> { const [isShow, setIsShow] = React.useState<boolean>(show);
constructor(props: Props) { const [disabled, setDisabled] = React.useState<boolean>(false);
super(props);
this.state = { React.useEffect(() => {
show: props.show, if (show) {
disabled: false, setDisabled(true);
}
}, [show]);
const handleChangeCheckbox: React.ChangeEventHandler<HTMLInputElement> = (e) => {
const disabled = e.target.value === '0';
setDisabled(disabled);
}; };
this.handleChangeCheckbox = this.handleChangeCheckbox.bind(this);
this.handleClickDownload = this.handleClickDownload.bind(this);
this.handleClickCancel = this.handleClickCancel.bind(this);
}
static getDerivedStateFromProps(nextProps: Props, prevState: State) { const handleClickDownload: React.MouseEventHandler<HTMLButtonElement> = () => {
if (nextProps.show && !prevState.show) { unsetShow();
return { disabled: true, show: nextProps.show }; setIsShow(false);
} };
return null;
}
handleChangeCheckbox(e: ChangeEvent<HTMLInputElement>) { const handleClickCancel = () => {
const disabled = e.target.value === "0"; unsetShow();
this.setState({ disabled }); setIsShow(false);
} };
handleClickDownload(e: MouseEvent<HTMLButtonElement>) { const renderBackdrop = (props: RenderModalBackdropProps) => {
this.props.unsetShow();
this.setState({ show: false });
}
handleClickCancel() {
this.props.unsetShow();
this.setState({ show: false });
}
renderBackdrop(props: any) {
return <div className={styles.overlay} {...props} />; return <div className={styles.overlay} {...props} />;
} };
render() { const date = new Date(file.timestamp);
const { lang, type } = this.props;
const date = new Date(this.props.file.timestamp);
const timestamp = Math.floor(date.valueOf() / 1000); const timestamp = Math.floor(date.valueOf() / 1000);
const url = ItemUtil.getFileUrl(type, this.props.file); const url = ItemUtil.getFileUrl(type, file);
return ( return (
<Modal className={styles.dialog} show={this.state.show} onHide={this.handleClickCancel} renderBackdrop={this.renderBackdrop}> <Modal
className={styles.dialog}
show={isShow}
onHide={handleClickCancel}
renderBackdrop={renderBackdrop}
>
<div> <div>
<div> <div>
{Functions.mlang("[en]Download file information[/en][ja]ダウンロードするファイルの情報[/ja]", lang)} {Functions.mlang(
'[en]Download file information[/en][ja]ダウンロードするファイルの情報[/ja]',
lang,
)}
<div className={styles.box}> <div className={styles.box}>
{this.props.file.original_file_name} {file.original_file_name}
<br /> <br />
<table> <table>
<tbody> <tbody>
<tr> <tr>
<td>Type</td> <td>Type</td>
<td>: {this.props.file.mime_type}</td> <td>: {file.mime_type}</td>
</tr> </tr>
<tr> <tr>
<td>Size</td> <td>Size</td>
<td> <td>
: <FileSize lang={lang} size={this.props.file.file_size} /> : <FileSize lang={lang} size={file.file_size} />
</td> </td>
</tr> </tr>
<tr> <tr>
@ -100,16 +97,43 @@ class LicenseAgreementDialog extends React.Component<Props, State> {
</div> </div>
<br /> <br />
<div> <div>
{Functions.mlang("[en]License agreement[/en][ja]ファイルのライセンス[/ja]", lang)} {Functions.mlang('[en]License agreement[/en][ja]ファイルのライセンス[/ja]', lang)}
<div className={styles.box}> <div className={styles.box}>
{Functions.mlang("[en]Please read the following license agreement carefully.[/en][ja]このファイルには下記のライセンスが設定されています。[/ja]", lang)} {Functions.mlang(
'[en]Please read the following license agreement carefully.[/en][ja]このファイルには下記のライセンスが設定されています。[/ja]',
lang,
)}
<div> <div>
<Rights lang={lang} rights={this.props.rights} useCc={this.props.useCc} ccCommercialUse={this.props.ccCommercialUse} ccModification={this.props.ccModification} /> <Rights
<input type="radio" name="radio_license" value="1" onChange={this.handleChangeCheckbox} checked={!this.state.disabled} /> lang={lang}
{Functions.mlang("[en]I accept the terms in the license agreement.[/en][ja]ライセンスに同意します。[/ja]", lang)} rights={rights}
useCc={useCc}
ccCommercialUse={ccCommercialUse}
ccModification={ccModification}
/>
<input
type="radio"
name="radio_license"
value="1"
onChange={handleChangeCheckbox}
checked={!disabled}
/>
{Functions.mlang(
'[en]I accept the terms in the license agreement.[/en][ja]ライセンスに同意します。[/ja]',
lang,
)}
<br /> <br />
<input type="radio" name="radio_license" value="0" onChange={this.handleChangeCheckbox} checked={this.state.disabled} /> <input
{Functions.mlang("[en]I do not accept the terms in the license agreement.[/en][ja]ライセンスに同意しません。[/ja]", lang)} type="radio"
name="radio_license"
value="0"
onChange={handleChangeCheckbox}
checked={disabled}
/>
{Functions.mlang(
'[en]I do not accept the terms in the license agreement.[/en][ja]ライセンスに同意しません。[/ja]',
lang,
)}
<br /> <br />
</div> </div>
</div> </div>
@ -118,19 +142,18 @@ class LicenseAgreementDialog extends React.Component<Props, State> {
<div className={styles.download}> <div className={styles.download}>
Acceptance is needed to download this file. Acceptance is needed to download this file.
<br /> <br />
<a href={url} download={this.props.file.original_file_name}> <a href={url} download={file.original_file_name}>
<button className="formButton" onClick={this.handleClickDownload} disabled={this.state.disabled}> <button className="formButton" onClick={handleClickDownload} disabled={disabled}>
Download Download
</button> </button>
</a> </a>
<button className="formButton" onClick={this.handleClickCancel}> <button className="formButton" onClick={handleClickCancel}>
Cancel Cancel
</button> </button>
</div> </div>
</div> </div>
</Modal> </Modal>
); );
} };
}
export default LicenseAgreementDialog; export default LicenseAgreementDialog;

View File

@ -4,7 +4,7 @@
} }
.previewBox::after { .previewBox::after {
content: ""; content: '';
display: block; display: block;
clear: both; clear: both;
} }

View File

@ -1,10 +1,12 @@
import React from "react"; import React from 'react';
import Lightbox from "react-image-lightbox";
import "react-image-lightbox/style.css"; import Lightbox, { SlideImage } from 'yet-another-react-lightbox';
import { BrainAtlasType, MultiLang } from "../../../../config"; import { BrainAtlasType, MultiLang } from '../../../../config';
import Functions from "../../../../functions"; import Functions from '../../../../functions';
import ItemUtil, { ItemBasicFile } from "../../../lib/ItemUtil"; import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil';
import styles from "./Preview.module.css";
import 'yet-another-react-lightbox/styles.css';
import styles from './Preview.module.css';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -12,34 +14,25 @@ interface Props {
type: BrainAtlasType; type: BrainAtlasType;
} }
interface State { const Preview: React.FC<Props> = (props) => {
isOpen: boolean; const { lang, file, type } = props;
imageIndex: number;
}
class Preview extends React.Component<Props, State> { const [isOpen, setIsOpen] = React.useState<boolean>(false);
constructor(props: Props) { const [imageIndex, setImageIndex] = React.useState<number>(0);
super(props);
this.state = {
isOpen: false,
imageIndex: 0,
};
}
render() {
const { lang, file, type } = this.props;
const data = file.filter((value) => { const data = file.filter((value) => {
return value.file_type_name === "preview"; return value.file_type_name === 'preview';
}); });
if (data.length === 0) { if (data.length === 0) {
return null; return null;
} }
let imageUrls: string[] = []; const slides: SlideImage[] = [];
const previews = data.map((value, idx) => { const previews = data.map((value, idx) => {
const fileUrl = ItemUtil.getFileUrl(type, value); const fileUrl = ItemUtil.getFileUrl(type, value);
const previewUrl = ItemUtil.getPreviewFileUrl(type, value); const previewUrl = ItemUtil.getPreviewFileUrl(type, value);
const caption = Functions.mlang(value.caption, lang); const caption = Functions.mlang(value.caption, lang);
imageUrls.push(fileUrl); slides.push({ src: fileUrl });
return ( return (
<figure key={value.file_id} className={styles.preview}> <figure key={value.file_id} className={styles.preview}>
<a <a
@ -47,7 +40,8 @@ class Preview extends React.Component<Props, State> {
download={value.original_file_name} download={value.original_file_name}
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
this.setState({ isOpen: true, imageIndex: idx }); setIsOpen(true);
setImageIndex(idx);
}} }}
> >
<img src={previewUrl} alt={caption} /> <img src={previewUrl} alt={caption} />
@ -56,31 +50,13 @@ class Preview extends React.Component<Props, State> {
</figure> </figure>
); );
}); });
const { isOpen, imageIndex } = this.state;
return ( return (
<> <>
<div className={styles.previewBox}>{previews}</div> <div className={styles.previewBox}>{previews}</div>
{isOpen && ( {isOpen && <Lightbox index={imageIndex} slides={slides} close={() => setIsOpen(false)} />}
<Lightbox
mainSrc={imageUrls[imageIndex]}
nextSrc={imageUrls[(imageIndex + 1) % data.length]}
prevSrc={imageUrls[(imageIndex + data.length - 1) % data.length]}
onCloseRequest={() => this.setState({ isOpen: false })}
onMovePrevRequest={() =>
this.setState({
imageIndex: (imageIndex + data.length - 1) % data.length,
})
}
onMoveNextRequest={() =>
this.setState({
imageIndex: (imageIndex + 1) % data.length,
})
}
/>
)}
</> </>
); );
} };
}
export default Preview; export default Preview;

View File

@ -1,6 +1,7 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config";
import DateTime from "./DateTime"; import { MultiLang } from '../../../../config';
import DateTime from './DateTime';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -9,9 +10,9 @@ interface Props {
mday: number; mday: number;
} }
const PublicationDate: React.FC<Props> = (props: Props) => { const PublicationDate: React.FC<Props> = (props) => {
const { lang, year, month, mday } = props; const { lang, year, month, mday } = props;
const d = new Date(year + "-" + month + "-" + mday); const d = new Date(year + '-' + month + '-' + mday);
const timestamp = Math.floor(d.valueOf() / 1000); const timestamp = Math.floor(d.valueOf() / 1000);
return <DateTime lang={lang} date={timestamp} onlyDate={true} />; return <DateTime lang={lang} date={timestamp} onlyDate={true} />;
}; };

View File

@ -1,13 +1,14 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config";
import Description from "./Description"; import { MultiLang } from '../../../../config';
import Description from './Description';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
readme: string; readme: string;
} }
const Readme: React.FC<Props> = (props: Props) => { const Readme: React.FC<Props> = (props) => {
const { lang, readme } = props; const { lang, readme } = props;
return <Description lang={lang} description={readme} className="readme" />; return <Description lang={lang} description={readme} className="readme" />;
}; };

View File

@ -1,7 +1,8 @@
import React from "react"; import React from 'react';
import { BrainAtlasType, MultiLang } from "../../../../config";
import ItemType from "../../../item-type"; import { BrainAtlasType, MultiLang } from '../../../../config';
import ItemUtil from "../../../lib/ItemUtil"; import ItemType from '../../../item-type';
import ItemUtil from '../../../lib/ItemUtil';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -9,44 +10,26 @@ interface Props {
type: BrainAtlasType; type: BrainAtlasType;
} }
interface State { const RelatedTo: React.FC<Props> = (props) => {
elements: JSX.Element[]; const { lang, relatedTo, type } = props;
} const isMounted = React.useRef<boolean>(false);
class RelatedTo extends React.Component<Props, State> { const [elements, setElements] = React.useState<React.ReactNode[]>([]);
private isActive: boolean;
constructor(props: Props) { React.useEffect(() => {
super(props); isMounted.current = true;
this.state = { return () => {
elements: [], isMounted.current = false;
}; };
this.isActive = false; }, []);
}
componentDidMount() { React.useEffect(() => {
this.isActive = true;
this.updateElements(this.props.relatedTo);
}
componentDidUpdate(prevProps: Props) {
if (JSON.stringify(this.props.relatedTo) !== JSON.stringify(prevProps.relatedTo)) {
this.updateElements(this.props.relatedTo);
}
}
componentWillUnmount() {
this.isActive = false;
}
updateElements(relatedTo: number[]) {
const { lang, type } = this.props;
if (relatedTo.length === 0) { if (relatedTo.length === 0) {
this.setState({ elements: [] }); setElements([]);
} else { } else {
ItemUtil.getList(type, relatedTo, (results) => { ItemUtil.getList(type, relatedTo, (results) => {
const elements = results.data.map((item, idx) => { const elements = results.data.map((item, idx) => {
const evenodd = idx % 0 ? "even" : "odd"; const evenodd = idx % 0 ? 'even' : 'odd';
return ( return (
<tr key={item.item_id}> <tr key={item.item_id}>
<td className={evenodd}> <td className={evenodd}>
@ -55,15 +38,14 @@ class RelatedTo extends React.Component<Props, State> {
</tr> </tr>
); );
}); });
if (this.isActive) { if (isMounted.current) {
this.setState({ elements }); setElements(elements);
} }
}); });
} }
} }, [lang, relatedTo, type]);
render() { if (elements.length === 0) {
if (this.state.elements.length === 0) {
return null; return null;
} }
return ( return (
@ -72,11 +54,10 @@ class RelatedTo extends React.Component<Props, State> {
<tr> <tr>
<th>Item summary</th> <th>Item summary</th>
</tr> </tr>
{this.state.elements} {elements}
</tbody> </tbody>
</table> </table>
); );
} };
}
export default RelatedTo; export default RelatedTo;

View File

@ -1,7 +1,8 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config";
import CreativeCommons, { getCreativeCommonsType } from "./CreativeCommons"; import { MultiLang } from '../../../../config';
import Description from "./Description"; import CreativeCommons from './CreativeCommons';
import Description from './Description';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -11,13 +12,18 @@ interface Props {
ccModification: number; ccModification: number;
} }
const Rights: React.FC<Props> = (props: Props) => { const Rights: React.FC<Props> = (props) => {
const { lang, rights, useCc, ccCommercialUse, ccModification } = props; const { lang, rights, useCc, ccCommercialUse, ccModification } = props;
if (useCc === 0) { if (useCc === 0) {
return <Description lang={lang} description={rights} className="rights" />; return <Description lang={lang} description={rights} className="rights" />;
} }
const ccType = getCreativeCommonsType(ccCommercialUse, ccModification); return (
return <CreativeCommons lang={lang} type={ccType} />; <CreativeCommons
lang={lang}
ccCommercialUse={ccCommercialUse}
ccModification={ccModification}
/>
);
}; };
export default Rights; export default Rights;

View File

@ -1,6 +1,6 @@
import React from "react"; import React from 'react';
import { MultiLang } from "../../../../config"; import { MultiLang } from '../../../../config';
import imageButton from "../../../assets/images/simpf_button.png"; import imageButton from '../../../assets/images/simpf_button.png';
interface Props { interface Props {
lang: MultiLang; lang: MultiLang;
@ -8,11 +8,11 @@ interface Props {
isDetail: boolean; isDetail: boolean;
} }
const SimPFLinkIcon: React.FC<Props> = (props: Props) => { const SimPFLinkIcon: React.FC<Props> = (props) => {
const { url, isDetail } = props; const { url, isDetail } = props;
const title = "Online Simulation"; const title = 'Online Simulation';
const size = isDetail ? 64 : 35; const size = isDetail ? 64 : 35;
if (url === "") { if (url === '') {
return null; return null;
} }
return ( return (

View File

@ -1,25 +1,25 @@
import Author from "./Author"; import Author from './Author';
import ChangeLog from "./ChangeLog"; import ChangeLog from './ChangeLog';
import Contributer from "./Contributer"; import Contributor from './Contributor';
import CreativeCommons from "./CreativeCommons"; import CreativeCommons from './CreativeCommons';
import DateTime from "./DateTime"; import DateTime from './DateTime';
import Description from "./Description"; import Description from './Description';
import FileDownloadButton from "./FileDownloadButton"; import FileDownloadButton from './FileDownloadButton';
import FileSize from "./FileSize"; import FileSize from './FileSize';
import FreeKeyword from "./FreeKeyword"; import FreeKeyword from './FreeKeyword';
import ItemFile from "./ItemFile"; import ItemFile from './ItemFile';
import ItemIndex from "./ItemIndex"; import ItemIndex from './ItemIndex';
import Language from "./Language"; import Language from './Language';
import Preview from "./Preview"; import Preview from './Preview';
import PublicationDate from "./PublicationDate"; import PublicationDate from './PublicationDate';
import Readme from "./Readme"; import Readme from './Readme';
import RelatedTo from "./RelatedTo"; import RelatedTo from './RelatedTo';
import Rights from "./Rights"; import Rights from './Rights';
const ItemTypeField = { const ItemTypeField = {
Author, Author,
ChangeLog, ChangeLog,
Contributer, Contributor,
CreativeCommons, CreativeCommons,
DateTime, DateTime,
Description, Description,

View File

@ -1,24 +1,33 @@
import AdvancedSearchBase, { AdvancedSearchBaseProps } from "../lib/AdvancedSearchBase"; import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
class MemoAdvancedSearch extends AdvancedSearchBase { class MemoAdvancedSearch extends AdvancedSearchBase {
constructor(props: AdvancedSearchBaseProps) { constructor(props: AdvancedSearchBaseProps) {
super(props); super(props);
this.type = "memo"; this.type = 'memo';
this.title = "Memo"; this.title = 'Memo';
this.state.values["title"] = ""; this.state.values.title = '';
this.state.values["keyword"] = ""; this.state.values.keyword = '';
this.state.values["description"] = ""; this.state.values.description = '';
this.state.values["doi"] = ""; this.state.values.doi = '';
this.state.values["item_link"] = ""; this.state.values.item_link = '';
} }
getRows() { getRows() {
const rows = [ const rows = [
{ label: "[en]Title[/en][ja]タイトル[/ja]", value: this.renderFieldInputText("title", 50) }, { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) },
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: this.renderFieldInputText("keyword", 50) }, {
{ label: "[en]Description[/en][ja]概要[/ja]", value: this.renderFieldInputText("description", 50) }, label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
{ label: "ID", value: this.renderFieldInputText("doi", 50) }, value: this.renderFieldInputText('keyword', 50),
{ label: "[en]Item Link[/en][ja]リンク[/ja]", value: this.renderFieldInputText("item_link", 50) }, },
{
label: '[en]Description[/en][ja]概要[/ja]',
value: this.renderFieldInputText('description', 50),
},
{ label: 'ID', value: this.renderFieldInputText('doi', 50) },
{
label: '[en]Item Link[/en][ja]リンク[/ja]',
value: this.renderFieldInputText('item_link', 50),
},
]; ];
return rows; return rows;
} }

View File

@ -1,29 +1,63 @@
import React from "react"; import XoopsCode from '../../../common/lib/XoopsCode';
import XoopsCode from "../../../common/lib/XoopsCode"; import Functions from '../../../functions';
import Functions from "../../../functions"; import { ItemMemo } from '../../lib/ItemUtil';
import { ItemMemo } from "../../lib/ItemUtil"; import DetailBase from '../lib/DetailBase';
import DetailBase from "../lib/DetailBase"; import ItemTypeField from '../lib/field';
import ItemTypeField from "../lib/field";
class MemoDetail extends DetailBase { class MemoDetail extends DetailBase {
getFields() { getFields() {
const { lang, type } = this.props; const { lang, type } = this.props;
const item = this.props.item as ItemMemo; const item = this.props.item as ItemMemo;
const fields = [ const fields = [
{ label: "ID", value: item.doi }, { label: 'ID', value: item.doi },
{ label: "[en]Language[/en][ja]言語[/ja]", value: <ItemTypeField.Language lang={lang} itemLang={item.lang} /> }, {
{ label: "[en]Title[/en][ja]タイトル[/ja]", value: Functions.mlang(item.title, lang) }, label: '[en]Language[/en][ja]言語[/ja]',
{ label: "[en]Free Keywords[/en][ja]フリーキーワード[/ja]", value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} /> }, value: <ItemTypeField.Language lang={lang} itemLang={item.lang} />,
{ label: "[en]Description[/en][ja]概要[/ja]", value: <ItemTypeField.Description lang={lang} description={item.description} /> }, },
{ label: "[en]Last Modified Date[/en][ja]最終更新日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} /> }, { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) },
{ label: "[en]Created Date[/en][ja]作成日[/ja]", value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} /> }, {
{ label: "[en]Contributor[/en][ja]登録者[/ja]", value: <ItemTypeField.Contributer lang={lang} uname={item.uname} name={item.name} /> }, label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]',
{ label: "[en]Item Type[/en][ja]アイテムタイプ[/ja]", value: item.item_type_display_name }, value: <ItemTypeField.FreeKeyword lang={lang} keyword={item.keyword} />,
{ label: "[en]Change Log(History)[/en][ja]変更履歴[/ja]", value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} /> }, },
{ label: "[en]Item Link[/en][ja]リンク[/ja]", value: <XoopsCode lang={lang} text={item.item_link} /> }, {
{ label: "[en]Memo File[/en][ja]メモファイル[/ja]", value: <ItemTypeField.ItemFile lang={lang} file={item.file} ftype="memo_file" type={type} /> }, label: '[en]Description[/en][ja]概要[/ja]',
{ label: "Index", value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} /> }, value: <ItemTypeField.Description lang={lang} description={item.description} />,
{ label: "[en]Related to[/en][ja]関連アイテム[/ja]", value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} /> }, },
{
label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.last_update_date} />,
},
{
label: '[en]Created Date[/en][ja]作成日[/ja]',
value: <ItemTypeField.DateTime lang={lang} date={item.creation_date} />,
},
{
label: '[en]Contributor[/en][ja]登録者[/ja]',
value: <ItemTypeField.Contributor lang={lang} uname={item.uname} name={item.name} />,
},
{ label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name },
{
label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]',
value: <ItemTypeField.ChangeLog lang={lang} changelog={item.changelog} />,
},
{
label: '[en]Item Link[/en][ja]リンク[/ja]',
value: <XoopsCode lang={lang} text={item.item_link} />,
},
{
label: '[en]Memo File[/en][ja]メモファイル[/ja]',
value: (
<ItemTypeField.ItemFile lang={lang} file={item.file} fileType="memo_file" type={type} />
),
},
{
label: 'Index',
value: <ItemTypeField.ItemIndex lang={lang} index={item.index} type={type} />,
},
{
label: '[en]Related to[/en][ja]関連アイテム[/ja]',
value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} type={type} />,
},
]; ];
return fields; return fields;
} }

View File

@ -1,22 +1,21 @@
import React from "react"; import { Link } from 'react-router-dom';
import { Link } from "react-router-dom"; import XoopsCode from '../../../common/lib/XoopsCode';
import XoopsCode from "../../../common/lib/XoopsCode"; import Functions from '../../../functions';
import Functions from "../../../functions"; import iconFile from '../../assets/images/icon_memo.gif';
import iconFile from "../../assets/images/icon_memo.gif"; import { ItemMemo } from '../../lib/ItemUtil';
import { ItemMemo } from "../../lib/ItemUtil"; import ListBase, { ListBaseProps } from '../lib/ListBase';
import ListBase, { ListBaseProps } from "../lib/ListBase";
class MemoList extends ListBase { class MemoList extends ListBase {
constructor(props: ListBaseProps) { constructor(props: ListBaseProps) {
super(props); super(props);
this.label = "Memo"; this.label = 'Memo';
this.icon = iconFile; this.icon = iconFile;
} }
renderBody() { renderBody() {
const { lang } = this.props; const { lang } = this.props;
const item = this.props.item as ItemMemo; const item = this.props.item as ItemMemo;
const link = item.item_link !== "" ? <XoopsCode lang={lang} text={item.item_link} /> : null; const link = item.item_link !== '' ? <XoopsCode lang={lang} text={item.item_link} /> : null;
return ( return (
<> <>
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link> <Link to={this.url}>{Functions.mlang(item.title, lang)}</Link>

View File

@ -1,13 +1,13 @@
import iconFile from "../../assets/images/icon_memo.gif"; import iconFile from '../../assets/images/icon_memo.gif';
import TopBase, { TopBaseProps } from "../lib/TopBase"; import TopBase, { TopBaseProps } from '../lib/TopBase';
class MemoTop extends TopBase { class MemoTop extends TopBase {
constructor(props: TopBaseProps) { constructor(props: TopBaseProps) {
super(props); super(props);
this.type = "memo"; this.type = 'memo';
this.label = "Memo"; this.label = 'Memo';
this.icon = iconFile; this.icon = iconFile;
this.description = "[en]Personal Memo Pad.[/en][ja]汎用メモパッド[/ja]"; this.description = '[en]Personal Memo Pad.[/en][ja]汎用メモパッド[/ja]';
} }
} }

Some files were not shown because too many files have changed in this diff Show More