update required libraries.
@@ -0,0 +1,70 @@
|
||||
.database {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.database :global(.list) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.database :global(.listTable) {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 5px;
|
||||
}
|
||||
|
||||
.database :global(.listTable .listIcon),
|
||||
.database :global(.listTable .listExtra) {
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
width: 65px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.database :global(.itemDetail) {
|
||||
border-collapse: separate;
|
||||
border-spacing: 1px;
|
||||
}
|
||||
.database :global(.itemDetail .head) {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.database :global(.itemDetail .readme),
|
||||
.database :global(.itemDetail .rights) {
|
||||
background-color: #ffffff;
|
||||
width: 100%;
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.database :global(.advancedSearch .head) {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.database :global(.advancedSearch .search) {
|
||||
text-align: center;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.database :global(.advancedSearch .itemtype) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.database :global(.advancedSearch .itemtype .itemtypeName),
|
||||
.database :global(.advancedSearch .itemtype .itemtypeFields) {
|
||||
border-collapse: separate;
|
||||
border-spacing: 1px;
|
||||
}
|
||||
|
||||
.database :global(.advancedSearch .itemtype .itemtypeName th) {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.database :global(.advancedSearch .fieldDateLabel) {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.database :global(.advancedSearch .fieldDate select),
|
||||
.database :global(.advancedSearch .fieldDate input) {
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { Route, RouteComponentProps, Switch } from 'react-router-dom';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import styles from './Database.module.css';
|
||||
import DatabaseAdvancedSearch from './DatabaseAdvancedSearch';
|
||||
import DatabaseDetailItem from './DatabaseDetailItem';
|
||||
import DatabaseSearchByAdvancedKeyword from './DatabaseSearchByAdvancedKeyword';
|
||||
import DatabaseSearchByIndexId from './DatabaseSearchByIndexId';
|
||||
import DatabaseSearchByItemType from './DatabaseSearchByItemType';
|
||||
import DatabaseSearchByKeyword from './DatabaseSearchByKeyword';
|
||||
import DatabaseTop from './DatabaseTop';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
const Database = (props: Props) => {
|
||||
const { lang } = props;
|
||||
return (
|
||||
<div className={styles.database}>
|
||||
<Helmet>
|
||||
<title>{Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<Switch>
|
||||
<Route exact path="/database" render={(props: RouteComponentProps) => <DatabaseTop lang={lang} {...props} />} />
|
||||
<Route exact path="/database/item/:id" render={(props: RouteComponentProps<{ id: string; doi: string }>) => <DatabaseDetailItem lang={lang} {...props} />} />
|
||||
<Route exact path="/database/item/id/:doi" render={(props: RouteComponentProps<{ id: string; doi: string }>) => <DatabaseDetailItem lang={lang} {...props} />} />
|
||||
<Route exact path="/database/advanced" render={(props: RouteComponentProps) => <DatabaseAdvancedSearch lang={lang} {...props} />} />
|
||||
<Route exact path="/database/list" render={(props: RouteComponentProps<{ id: string }>) => <DatabaseSearchByIndexId lang={lang} {...props} />} />
|
||||
<Route exact path="/database/list/:id" render={(props: RouteComponentProps<{ id: string }>) => <DatabaseSearchByIndexId lang={lang} {...props} />} />
|
||||
<Route exact path="/database/search" render={(props: RouteComponentProps) => <DatabaseSearchByKeyword lang={lang} {...props} />} />
|
||||
<Route exact path="/database/search/advanced" render={(props: RouteComponentProps) => <DatabaseSearchByAdvancedKeyword lang={lang} {...props} />} />
|
||||
<Route exact path="/database/search/itemtype/:itemType" render={(props: RouteComponentProps<{ itemType: string; subItemType: string }>) => <DatabaseSearchByItemType lang={lang} {...props} />} />
|
||||
<Route exact path="/database/search/itemtype/:itemType/:subItemType" render={(props: RouteComponentProps<{ itemType: string; subItemType: string }>) => <DatabaseSearchByItemType lang={lang} {...props} />} />
|
||||
<Route component={PageNotFound} />
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Database;
|
||||
@@ -0,0 +1,48 @@
|
||||
import React, { Component } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import Config, { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import ItemType from './item-type';
|
||||
import AdvancedSearchQuery from './lib/AdvancedSearchQuery';
|
||||
import ItemUtil from './lib/ItemUtil';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
class DatabaseAdvancedSearch extends Component<Props> {
|
||||
|
||||
private query: AdvancedSearchQuery = new AdvancedSearchQuery();
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.handleClickSearchButton = this.handleClickSearchButton.bind(this);
|
||||
}
|
||||
|
||||
handleClickSearchButton() {
|
||||
if (!this.query.empty()) {
|
||||
const url = ItemUtil.getSearchByAdvancedKeywordsUrl(this.query);
|
||||
this.props.history.push(url);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
return (
|
||||
<div className="advancedSearch">
|
||||
<h3>{Functions.mlang('[en]Search Items[/en][ja]アイテム検索[/ja]', lang)}</h3>
|
||||
<div className="search">
|
||||
<button className="formButton" onClick={this.handleClickSearchButton}>Search</button>
|
||||
</div>
|
||||
{Config.XOONIPS_ITEMTYPES.map((type) => {
|
||||
return <ItemType.AdvancedSearch key={type} type={'xnp' + type} lang={lang} query={this.query} />;
|
||||
})}
|
||||
<div className="search">
|
||||
<button className="formButton" onClick={this.handleClickSearchButton}>Search</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DatabaseAdvancedSearch;
|
||||
@@ -0,0 +1,89 @@
|
||||
import React, { Component } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import Loading from '../common/lib/Loading';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import ItemType from './item-type';
|
||||
import ItemUtil, { Item } from './lib/ItemUtil';
|
||||
|
||||
interface Params {
|
||||
id: string;
|
||||
doi: string;
|
||||
}
|
||||
|
||||
interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
interface State {
|
||||
loading: boolean;
|
||||
item: Item | null;
|
||||
}
|
||||
|
||||
class DatabaseDetailItem extends Component<Props, State> {
|
||||
|
||||
private id: number;
|
||||
private doi: string;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
item: null,
|
||||
};
|
||||
const { params } = this.props.match;
|
||||
this.id = typeof params.id !== 'undefined' ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : 0;
|
||||
this.doi = typeof params.doi !== 'undefined' ? params.doi : '';
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateItem();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { params } = this.props.match;
|
||||
const id = typeof params.id !== 'undefined' ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : 0;
|
||||
const doi = typeof params.doi !== 'undefined' ? params.doi : '';
|
||||
if (this.id !== id || this.doi !== doi) {
|
||||
this.id = id;
|
||||
this.doi = doi;
|
||||
this.updateItem();
|
||||
}
|
||||
}
|
||||
|
||||
updateItem() {
|
||||
if (this.doi !== '') {
|
||||
ItemUtil.getByDoi(this.doi, (item) => {
|
||||
this.setState({ loading: false, item });
|
||||
});
|
||||
} else if (this.id !== 0) {
|
||||
ItemUtil.get(this.id, (item) => {
|
||||
this.setState({ loading: false, item });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
if (this.state.loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
if (this.state.item === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{Functions.mlang(this.state.item.title, lang)} - {Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<h3>{Functions.mlang('[en]Detail[/en][ja]詳細[/ja]', lang)}</h3>
|
||||
<br />
|
||||
<ItemType.Detail lang={lang} item={this.state.item} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DatabaseDetailItem;
|
||||
@@ -0,0 +1,56 @@
|
||||
import React, { Component } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { MultiLang } from '../config';
|
||||
import AdvancedSearchQuery from './lib/AdvancedSearchQuery';
|
||||
import DatabaseListItem from './lib/DatabaseListItem';
|
||||
import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang
|
||||
}
|
||||
|
||||
interface State {
|
||||
search: string;
|
||||
query: AdvancedSearchQuery;
|
||||
}
|
||||
|
||||
class DatabaseSearchByAdvancedKeyword extends Component<Props, State> {
|
||||
|
||||
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() {
|
||||
return ItemUtil.getSearchByAdvancedKeywordsUrl(this.state.query);
|
||||
}
|
||||
|
||||
searchFunc(condition: SortCondition, func: SearchCallbackFunc) {
|
||||
ItemUtil.getListByAdvancedSearchQuery(this.state.query, condition, func);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const baseUrl = this.getUrl();
|
||||
return (
|
||||
<div className="list">
|
||||
<h3>Listing item</h3>
|
||||
<DatabaseListItem lang={lang} url={baseUrl} search={this.searchFunc} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DatabaseSearchByAdvancedKeyword;
|
||||
@@ -0,0 +1,88 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import DatabaseListIndex from './lib/DatabaseListIndex';
|
||||
import DatabaseListItem from './lib/DatabaseListItem';
|
||||
import IndexUtil, { Index, INDEX_ID_PUBLIC } from './lib/IndexUtil';
|
||||
import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil';
|
||||
|
||||
interface Params {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
interface State {
|
||||
indexId: number;
|
||||
}
|
||||
|
||||
class DatabaseSearchByIndexId extends Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { params } = props.match;
|
||||
this.state = {
|
||||
indexId: params.id ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : INDEX_ID_PUBLIC,
|
||||
}
|
||||
this.searchFunc = this.searchFunc.bind(this);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||
const { params } = nextProps.match;
|
||||
const indexId = params.id ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : INDEX_ID_PUBLIC;
|
||||
if (prevState.indexId !== indexId) {
|
||||
return { indexId };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
if (this.state.indexId === 0) {
|
||||
return '/';
|
||||
}
|
||||
return IndexUtil.getUrl(this.state.indexId);
|
||||
}
|
||||
|
||||
searchFunc(condition: SortCondition, func: SearchCallbackFunc) {
|
||||
if (this.state.indexId === 0) {
|
||||
const res = { total: 0, data: [] };
|
||||
func(res);
|
||||
} else {
|
||||
ItemUtil.getListByIndexId(this.state.indexId, condition, func);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const index = IndexUtil.get(this.state.indexId);
|
||||
if (index === null) {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
const baseUrl = this.getUrl();
|
||||
const pIndexes = IndexUtil.getParents(this.state.indexId);
|
||||
const parents = pIndexes.map((value: Index) => {
|
||||
const url: string = IndexUtil.getUrl(value.id);
|
||||
return <Fragment key={value.id}>/ <Link to={url}>{value.title}</Link> </Fragment>;
|
||||
});
|
||||
const title = pIndexes.map((value) => { return '/' + value.title; }).join('');
|
||||
return (
|
||||
<div className="list">
|
||||
<Helmet>
|
||||
<title>{Functions.mlang(title, lang)} - {Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} - {Functions.siteTitle(lang)}</title>
|
||||
</Helmet>
|
||||
<h3>{Functions.mlang('[en]Listing item[/en][ja]アイテム一覧[/ja]', lang)}</h3>
|
||||
<div>{parents}</div>
|
||||
<DatabaseListIndex lang={lang} index={index} />
|
||||
<DatabaseListItem lang={lang} url={baseUrl} search={this.searchFunc} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DatabaseSearchByIndexId;
|
||||
@@ -0,0 +1,73 @@
|
||||
import React, { Component } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import DatabaseListItem from './lib/DatabaseListItem';
|
||||
import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil';
|
||||
|
||||
interface Params {
|
||||
itemType: string;
|
||||
subItemType: string;
|
||||
}
|
||||
|
||||
interface Props extends RouteComponentProps<Params> {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
interface State {
|
||||
itemType: string;
|
||||
subItemType: string;
|
||||
}
|
||||
|
||||
class DatabaseSearchByItemType extends Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { params } = this.props.match;
|
||||
this.state = {
|
||||
itemType: params.itemType ? params.itemType : '',
|
||||
subItemType: params.subItemType ? params.subItemType : '',
|
||||
};
|
||||
this.searchFunc = this.searchFunc.bind(this);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||
const { params } = nextProps.match;
|
||||
const item_type = params.itemType ? params.itemType : '';
|
||||
const sub_item_type = params.subItemType ? params.subItemType : '';
|
||||
if (prevState.itemType !== item_type || prevState.subItemType !== sub_item_type) {
|
||||
return { item_type, sub_item_type };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
searchFunc(condition: SortCondition, func: SearchCallbackFunc) {
|
||||
if (this.state.itemType === '') {
|
||||
const res = { total: 0, data: [] };
|
||||
func(res);
|
||||
} else {
|
||||
ItemUtil.getListByItemType(this.state.itemType, this.state.subItemType, condition, func);
|
||||
}
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
let url = ItemUtil.getItemTypeSearchUrl(this.state.itemType);
|
||||
if (this.state.subItemType !== '') {
|
||||
url += '/' + this.state.subItemType;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const baseUrl = this.getUrl();
|
||||
return (
|
||||
<div className="list">
|
||||
<h3>{Functions.mlang('[en]Listing item[/en][ja]アイテム一覧[/ja]', lang)}</h3>
|
||||
<DatabaseListItem lang={lang} url={baseUrl} search={this.searchFunc} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DatabaseSearchByItemType;
|
||||
@@ -0,0 +1,60 @@
|
||||
import React, { Component } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
import DatabaseListItem from './lib/DatabaseListItem';
|
||||
import ItemUtil, { KeywordSearchType, SearchCallbackFunc, SortCondition } from './lib/ItemUtil';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
interface State {
|
||||
type: KeywordSearchType;
|
||||
keyword: string;
|
||||
}
|
||||
|
||||
class DatabaseSearchByKeyword extends Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { type, keyword } = ItemUtil.getSearchKeywordByQuery(this.props.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() {
|
||||
return ItemUtil.getSearchByKeywordUrl(this.state.type, this.state.keyword);
|
||||
}
|
||||
|
||||
searchFunc(condition: SortCondition, func: SearchCallbackFunc) {
|
||||
if (this.state.keyword === '') {
|
||||
const res = { total: 0, data: [] };
|
||||
func(res);
|
||||
} else {
|
||||
ItemUtil.getListByKeyword(this.state.type, this.state.keyword, condition, func);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = 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} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DatabaseSearchByKeyword;
|
||||
@@ -0,0 +1,13 @@
|
||||
.itemTypes .itemType {
|
||||
width: 50%;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.itemTypes .itemType :global(table) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.itemTypes .itemType :global(table .itemTypeName) {
|
||||
vertical-align: middle;
|
||||
font-size: large;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import Config, { MultiLang } from '../config';
|
||||
import styles from './DatabaseTop.module.css';
|
||||
import ItemType from './item-type';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
const DatabaseTop = (props: Props) => {
|
||||
const { lang } = props;
|
||||
const types: string[][] = [];
|
||||
const len = Config.XOONIPS_ITEMTYPES.length;
|
||||
for (let i = 0; i < Math.ceil(len / 2); i++) {
|
||||
const j = i * 2;
|
||||
const p = Config.XOONIPS_ITEMTYPES.slice(j, j + 2);
|
||||
types.push(p);
|
||||
}
|
||||
return (
|
||||
<table className={styles.itemTypes}>
|
||||
<tbody>
|
||||
{types.map((value, idx) => {
|
||||
return (
|
||||
<tr key={idx}>
|
||||
{value.map((type, idx) => {
|
||||
return (
|
||||
<td key={idx} className={styles.itemType}>
|
||||
{type !== '' && <ItemType.Top lang={lang} type={'xnp' + type} />}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
export default DatabaseTop;
|
||||
@@ -0,0 +1,150 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Redirect, RouteComponentProps, withRouter } from 'react-router';
|
||||
import PageNotFound from '../common/lib/PageNotFound';
|
||||
import { MultiLang } from '../config';
|
||||
import Functions from '../functions';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
class DatabaseXoopsPathRedirect extends Component<Props> {
|
||||
|
||||
getRedirectUrl(): string {
|
||||
const { location } = this.props;
|
||||
const pathname = location.pathname || '';
|
||||
const query = new URLSearchParams(location.search);
|
||||
const search = new RegExp('^/modules/xoonips(?:/+(.*))?$');
|
||||
const matches = pathname.match(search);
|
||||
if (matches === null) {
|
||||
return '';
|
||||
}
|
||||
const path = matches[1] || '';
|
||||
switch (path) {
|
||||
case '':
|
||||
case 'index.php': {
|
||||
return '/database';
|
||||
}
|
||||
case 'detail.php': {
|
||||
const id = query.get('id');
|
||||
if (id !== null) {
|
||||
return '/database/item/id/' + Functions.escape(id);
|
||||
}
|
||||
const itemId = query.get('item_id');
|
||||
if (itemId !== null && itemId.match(/^\d+$/) !== null) {
|
||||
return '/database/item/' + Functions.escape(itemId);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
case 'listitem.php': {
|
||||
const indexId = query.get('index_id');
|
||||
if (indexId !== null && indexId.match(/^\d+$/) !== null) {
|
||||
const params = new URLSearchParams();
|
||||
const map: any = {
|
||||
orderby: { key: 'orderby', isNumber: false },
|
||||
order_dir: { key: 'order_dir', isNumber: true },
|
||||
itemcount: { key: 'itemcount', isNumber: true },
|
||||
page: { key: 'page', isNumber: true }
|
||||
};
|
||||
for (let k in map) {
|
||||
const v = query.get(k);
|
||||
if (v === null || v.length === 0) {
|
||||
continue;
|
||||
}
|
||||
if (map[k].isNumber && v.match(/^\d+$/) !== null) {
|
||||
continue;
|
||||
}
|
||||
params.set(map[k].key, v);
|
||||
}
|
||||
const paramStr = params.toString();
|
||||
return '/database/list/' + Functions.escape(indexId) + (paramStr.length > 0 ? '?' + paramStr : '');
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'itemselect.php': {
|
||||
const op = query.get('op');
|
||||
if (op === null) {
|
||||
break;
|
||||
}
|
||||
switch (op) {
|
||||
case 'quicksearch': {
|
||||
const keyword = query.get('keyword');
|
||||
const itemType = query.get('search_itemtype');
|
||||
if (keyword === null || itemType === null || keyword === '') {
|
||||
return '';
|
||||
}
|
||||
const type = itemType.replace('xnp', '');
|
||||
if (itemType !== 'basic' && itemType !== 'all' && itemType.match(/^xnp.+/) === null) {
|
||||
return '';
|
||||
}
|
||||
const params = new URLSearchParams({ type, keyword });
|
||||
const map: any = {
|
||||
orderby: { key: 'orderby', isNumber: false },
|
||||
orderdir: { key: 'order_dir', isNumber: true },
|
||||
item_per_page: { key: 'itemcount', isNumber: true },
|
||||
page: { key: 'page', isNumber: true }
|
||||
};
|
||||
for (let k in map) {
|
||||
const v = query.get(k);
|
||||
if (v === null || v.length === 0) {
|
||||
continue;
|
||||
}
|
||||
if (map[k].isNumber && v.match(/^\d+$/) !== null) {
|
||||
continue;
|
||||
}
|
||||
params.set(map[k].key, v);
|
||||
}
|
||||
return '/database/search?' + params.toString();
|
||||
}
|
||||
case 'itemtypesearch': {
|
||||
const itemType = query.get('search_itemtype');
|
||||
if (itemType === null || itemType.match(/^xnp.+/) === null) {
|
||||
return '';
|
||||
}
|
||||
const type = itemType.replace('xnp', '');
|
||||
return '/database/search/itemtype/' + Functions.escape(type);
|
||||
}
|
||||
case 'itemsubtypesearch': {
|
||||
let type = '';
|
||||
let subtype = '';
|
||||
query.forEach((v, k) => {
|
||||
if (k.match(/^xnp[a-z]+$/) !== null && !!v) {
|
||||
type = k.replace('xnp', '');
|
||||
return;
|
||||
}
|
||||
})
|
||||
if (type === '') {
|
||||
return '';
|
||||
}
|
||||
query.forEach((v, k) => {
|
||||
if (k.match(`^xnp${type}_.+$`) !== null && !!v) {
|
||||
subtype = v;
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (subtype === '') {
|
||||
return '';
|
||||
}
|
||||
return '/database/search/itemtype/' + Functions.escape(type) + '/' + Functions.escape(subtype);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
case 'advanced_search.php': {
|
||||
return '/database/advanced';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const url = this.getRedirectUrl();
|
||||
if (url === '') {
|
||||
return <PageNotFound lang={lang} />;
|
||||
}
|
||||
return <Redirect to={url} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(DatabaseXoopsPathRedirect);
|
||||
|
After Width: | Height: | Size: 369 B |
|
After Width: | Height: | Size: 375 B |
|
After Width: | Height: | Size: 427 B |
|
After Width: | Height: | Size: 402 B |
|
After Width: | Height: | Size: 433 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 166 B |
|
After Width: | Height: | Size: 409 B |
|
After Width: | Height: | Size: 479 B |
|
After Width: | Height: | Size: 423 B |
|
After Width: | Height: | Size: 562 B |
|
After Width: | Height: | Size: 302 B |
|
After Width: | Height: | Size: 399 B |
|
After Width: | Height: | Size: 574 B |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 538 B |
|
After Width: | Height: | Size: 112 B |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -0,0 +1 @@
|
||||
[{"id":3,"title":"Public","num_of_items":32,"children":[{"id":6,"title":"Pupil Colloquium","num_of_items":0,"children":[{"id":216,"title":"2007, Hamamatsu","num_of_items":48,"children":[]},{"id":7,"title":"2005, Bear Mountain","num_of_items":28,"children":[]},{"id":81,"title":"2003, Crete","num_of_items":41,"children":[]},{"id":8,"title":"2001, Asilomar","num_of_items":32,"children":[]},{"id":82,"title":"1999, Nottingham","num_of_items":32,"children":[]},{"id":217,"title":"1997, Point Clear","num_of_items":31,"children":[]}]}]}]
|
||||
@@ -0,0 +1,91 @@
|
||||
.indexTree {
|
||||
border-top: 1px solid #999999;
|
||||
border-left: 1px solid #999999;
|
||||
border-bottom: 1px solid #404040;
|
||||
border-right: 1px solid #404040;
|
||||
background-color: white;
|
||||
height: 400px;
|
||||
width: calc(100% - 6px);
|
||||
overflow: auto;
|
||||
margin: 0 auto;
|
||||
padding: 3px;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.formButton {
|
||||
margin: 3px 3px 10px;
|
||||
}
|
||||
|
||||
.indexTree div span {
|
||||
color: #333;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
line-height: 19px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.indexTree div span:hover {
|
||||
color: #f60;
|
||||
}
|
||||
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode) {
|
||||
line-height: 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent) {
|
||||
display: inline-block;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit) {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 9px;
|
||||
background: url(../assets/images/tree_line.png);
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:not(:last-child)) {
|
||||
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) {
|
||||
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) {
|
||||
background-position: -27px 0;
|
||||
}
|
||||
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-switcher) {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 16px;
|
||||
margin-right: 2px;
|
||||
background: url(../assets/images/tree_node.png);
|
||||
cursor: pointer;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher-noop) {
|
||||
background-position: 0 0;
|
||||
cursor: auto;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher_open) {
|
||||
background-position: -16px 0;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher_close) {
|
||||
background-position: -32px 0;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher-noop) {
|
||||
background-position: 0 -20px;
|
||||
cursor: auto;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_open) {
|
||||
background-position: -16px -20px;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_close) {
|
||||
background-position: -32px -20px;
|
||||
}
|
||||
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-node-content-wrapper) {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-node-content-wrapper .rc-tree-title) {
|
||||
vertical-align: middle;
|
||||
line-height: 20px;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import Tree from 'rc-tree';
|
||||
import { DataNode, EventDataNode } from 'rc-tree/lib/interface';
|
||||
import React, { Component, ReactText } from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import { MultiLang } from '../../config';
|
||||
import Functions from '../../functions';
|
||||
import IndexUtil, { Index, INDEX_ID_PUBLIC } from '../lib/IndexUtil';
|
||||
import styles from './IndexTree.module.css';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
interface State {
|
||||
tree: DataNode[];
|
||||
expandableKeys: string[];
|
||||
expandedKeys: string[];
|
||||
selectedKeys: number[];
|
||||
}
|
||||
|
||||
class IndexTree extends Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.handleClickOpenAll = this.handleClickOpenAll.bind(this);
|
||||
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() {
|
||||
const { lang } = this.props;
|
||||
let keys: string[] = [];
|
||||
let eKeys: string[] = [];
|
||||
const makeTreeNode = (index: Index, depth: number): DataNode => {
|
||||
const title = Functions.mlang(index.title, lang) + (index.numOfItems > 0 ? ' (' + index.numOfItems + ')' : '');
|
||||
const children = IndexUtil.getChildren(index.id);
|
||||
if (children.length === 0) {
|
||||
return { key: String(index.id), title: title };
|
||||
}
|
||||
const childTreeNodes = children.map((value: Index) => {
|
||||
return makeTreeNode(value, depth + 1);
|
||||
});
|
||||
if (depth < 2) {
|
||||
eKeys.push(String(index.id));
|
||||
}
|
||||
keys.push(String(index.id));
|
||||
return { key: String(index.id), title: title, children: childTreeNodes };
|
||||
};
|
||||
let elements: DataNode[] = [];
|
||||
const index = IndexUtil.get(INDEX_ID_PUBLIC);
|
||||
if (index !== null) {
|
||||
elements.push(makeTreeNode(index, 0));
|
||||
}
|
||||
return {
|
||||
elements: elements,
|
||||
keys: keys,
|
||||
expandedKeys: eKeys,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props, prevState: State) {
|
||||
const { lang } = this.props;
|
||||
if (prevProps.lang !== lang) {
|
||||
const res = this.load();
|
||||
this.setState({
|
||||
tree: res.elements,
|
||||
selectedKeys: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleClickOpenAll() {
|
||||
this.setState({ expandedKeys: this.state.expandableKeys })
|
||||
}
|
||||
|
||||
handleClickCloseAll() {
|
||||
this.setState({ expandedKeys: [] })
|
||||
}
|
||||
|
||||
handleExpand(expandedKeys: ReactText[], info: {
|
||||
node: EventDataNode;
|
||||
expanded: boolean;
|
||||
nativeEvent: MouseEvent;
|
||||
}): void {
|
||||
const keys: string[] = expandedKeys.map((key) => {
|
||||
return typeof key === 'string' ? key : String(key);
|
||||
});
|
||||
this.setState({ expandedKeys: keys });
|
||||
}
|
||||
|
||||
handleSelect(selectedKeys: ReactText[], info: {
|
||||
event: 'select';
|
||||
selected: boolean;
|
||||
node: EventDataNode;
|
||||
selectedNodes: DataNode[];
|
||||
nativeEvent: MouseEvent;
|
||||
}): void {
|
||||
const selectedKey = selectedKeys.shift() || 0;
|
||||
const key = typeof selectedKey === 'string' ? parseInt(selectedKey, 10) : selectedKey;
|
||||
const url = IndexUtil.getUrl(key);
|
||||
this.props.history.push(url);
|
||||
this.setState({ selectedKeys: [] });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<button className={styles.formButton} onClick={this.handleClickOpenAll}>open all</button>
|
||||
<button className={styles.formButton} onClick={this.handleClickCloseAll}>close all</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} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(IndexTree);
|
||||
@@ -0,0 +1,7 @@
|
||||
.searchForm {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.inputKeyword {
|
||||
size: 16;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import React, { ChangeEvent, Component, FormEvent } from 'react';
|
||||
import { Link, RouteComponentProps, withRouter } from 'react-router-dom';
|
||||
import Config, { MultiLang } from '../../config';
|
||||
import Functions from '../../functions';
|
||||
import ItemUtil, { KeywordSearchType } from '../lib/ItemUtil';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
interface State {
|
||||
type: KeywordSearchType;
|
||||
keyword: string;
|
||||
pathname: string;
|
||||
}
|
||||
|
||||
class Search extends Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
type: 'all',
|
||||
keyword: '',
|
||||
pathname: '',
|
||||
};
|
||||
this.handleChangeType = this.handleChangeType.bind(this);
|
||||
this.handleChangeKeyword = this.handleChangeKeyword.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||
const pathname = nextProps.location.pathname;
|
||||
if (pathname !== prevState.pathname) {
|
||||
if (pathname === '/database/search') {
|
||||
const { type, keyword } = ItemUtil.getSearchKeywordByQuery(nextProps.location.search);
|
||||
return { type, keyword, pathname };
|
||||
}
|
||||
return {
|
||||
type: prevState.type,
|
||||
keyword: prevState.keyword,
|
||||
pathname
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
handleChangeKeyword(event: ChangeEvent<HTMLInputElement>) {
|
||||
const keyword = event.target.value.trim();
|
||||
this.setState({ keyword });
|
||||
}
|
||||
|
||||
handleChangeType(event: ChangeEvent<HTMLSelectElement>) {
|
||||
const type = event.target.value as KeywordSearchType;
|
||||
this.setState({ type });
|
||||
}
|
||||
|
||||
handleSubmit(event: FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
const url = ItemUtil.getSearchByKeywordUrl(this.state.type, this.state.keyword);
|
||||
this.props.history.push(url);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const options = [
|
||||
{ value: 'all', label: '[en]All[/en][ja]全て[/ja]' },
|
||||
{ value: 'basic', label: '[en]Title & Keyword[/en][ja]タイトル&キーワード[/ja]' },
|
||||
];
|
||||
Config.XOONIPS_ITEMTYPES.forEach((type) => {
|
||||
options.push({value: type, label: Functions.pascalCase(type)})
|
||||
});
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<input style={{width: '170px'}} type="text" value={this.state.keyword} onChange={this.handleChangeKeyword} />
|
||||
|
||||
<select value={this.state.type} onChange={this.handleChangeType}>
|
||||
{options.map((option) => {
|
||||
return <option key={option.value} value={option.value}>{Functions.mlang(option.label, lang)}</option>;
|
||||
})}
|
||||
</select>
|
||||
<br />
|
||||
<input className="formButton" type="submit" value="Search" />
|
||||
|
||||
<Link to="/database/advanced">{Functions.mlang('[en]Advanced[/en][ja]詳細検索[/ja]', lang)}</Link>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(Search);
|
||||
@@ -0,0 +1,26 @@
|
||||
import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
|
||||
|
||||
class BinderAdvancedSearch extends AdvancedSearchBase {
|
||||
|
||||
constructor(props: AdvancedSearchBaseProps) {
|
||||
super(props);
|
||||
this.type = 'binder';
|
||||
this.title = 'Binder';
|
||||
this.state.values['title'] = '';
|
||||
this.state.values['keyword'] = '';
|
||||
this.state.values['description'] = '';
|
||||
this.state.values['doi'] = '';
|
||||
}
|
||||
|
||||
getRows() {
|
||||
const rows = [
|
||||
{ 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: 'ID', value: this.renderFieldInputText('doi', 50) },
|
||||
];
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
export default BinderAdvancedSearch;
|
||||
@@ -0,0 +1,95 @@
|
||||
import React, { Component } from 'react';
|
||||
import Functions from '../../../functions';
|
||||
import ItemUtil, { ItemBinder, Item } from '../../lib/ItemUtil';
|
||||
import DetailBase from '../lib/DetailBase';
|
||||
import ItemTypeField from '../lib/field';
|
||||
import { MultiLang } from '../../../config';
|
||||
import ItemType from '..';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
item: ItemBinder;
|
||||
}
|
||||
|
||||
interface State {
|
||||
items: Item[];
|
||||
}
|
||||
|
||||
class BinderLinkItems extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
items: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
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 } = this.props;
|
||||
const itemIds = item.item_link;
|
||||
ItemUtil.getList(itemIds, (results) => {
|
||||
const items = results.data;
|
||||
this.setState({ items });
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
return (
|
||||
<table className="listTable">
|
||||
<tbody>
|
||||
{this.state.items.map((item, idx) => {
|
||||
const evenodd = idx % 2 ? 'even' : 'odd';
|
||||
return <tr key={item.item_id}><td className={evenodd}><ItemType.List lang={lang} item={item} /></td></tr>;
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BinderDetail extends DetailBase {
|
||||
|
||||
getFields() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemBinder;
|
||||
return [
|
||||
{ label: 'ID', value: item.doi },
|
||||
{ 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]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: 'Index', value: <ItemTypeField.ItemIndex lang={lang} index={item.index} /> },
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemBinder;
|
||||
const detail = super.render.call(this);
|
||||
return (
|
||||
<>
|
||||
{detail}
|
||||
<h4>Registered Items</h4>
|
||||
<BinderLinkItems lang={lang} item={item} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default BinderDetail;
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Functions from '../../../functions';
|
||||
import iconFile from '../../assets/images/icon_binder.gif';
|
||||
import { ItemBinder } from '../../lib/ItemUtil';
|
||||
import ListBase, { ListBaseProps } from '../lib/ListBase';
|
||||
|
||||
class BinderList extends ListBase {
|
||||
|
||||
constructor(props: ListBaseProps) {
|
||||
super(props);
|
||||
this.label = 'Binder';
|
||||
this.icon = iconFile;
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemBinder;
|
||||
return (
|
||||
<>
|
||||
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link><br />
|
||||
{Functions.mlang(item.description, lang)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default BinderList;
|
||||
@@ -0,0 +1,15 @@
|
||||
import TopBase, { TopBaseProps } from '../lib/TopBase';
|
||||
import iconFile from '../../assets/images/icon_binder.gif';
|
||||
|
||||
class BinderTop extends TopBase {
|
||||
|
||||
constructor(props: TopBaseProps) {
|
||||
super(props);
|
||||
this.type = 'binder';
|
||||
this.label = 'Binder';
|
||||
this.icon = iconFile;
|
||||
this.description = '[en]Binder collection.[/en][ja]バインダー[/ja]';
|
||||
}
|
||||
}
|
||||
|
||||
export default BinderTop;
|
||||
@@ -0,0 +1,13 @@
|
||||
import BinderAdvancedSearch from './BinderAdvancedSearch';
|
||||
import BinderDetail from './BinderDetail';
|
||||
import BinderList from './BinderList';
|
||||
import BinderTop from './BinderTop';
|
||||
|
||||
const ItemTypeBinder = {
|
||||
Top: BinderTop,
|
||||
List: BinderList,
|
||||
Detail: BinderDetail,
|
||||
AdvancedSearch: BinderAdvancedSearch,
|
||||
};
|
||||
|
||||
export default ItemTypeBinder;
|
||||
@@ -0,0 +1,38 @@
|
||||
import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
|
||||
|
||||
class BookAdvancedSearch extends AdvancedSearchBase {
|
||||
|
||||
constructor(props: AdvancedSearchBaseProps) {
|
||||
super(props);
|
||||
this.type = 'book';
|
||||
this.title = 'Book';
|
||||
this.state.values['title'] = '';
|
||||
this.state.values['keyword'] = '';
|
||||
this.state.values['description'] = '';
|
||||
this.state.values['doi'] = '';
|
||||
this.state.values['author'] = '';
|
||||
this.state.values['editor'] = '';
|
||||
this.state.values['publisher'] = '';
|
||||
this.state.values['publication_year'] = '';
|
||||
this.state.values['isbn'] = '';
|
||||
this.state.values['file.book_pdf.original_file_name'] = '';
|
||||
}
|
||||
|
||||
getRows() {
|
||||
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]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;
|
||||
}
|
||||
}
|
||||
|
||||
export default BookAdvancedSearch;
|
||||
@@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import Functions from '../../../functions';
|
||||
import { ItemBook } from '../../lib/ItemUtil';
|
||||
import DetailBase from '../lib/DetailBase';
|
||||
import ItemTypeField from '../lib/field';
|
||||
|
||||
class BookDetail extends DetailBase {
|
||||
|
||||
getFields() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemBook;
|
||||
return [
|
||||
{ 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', value: <a href={item.url} target="_blank" rel="noopener noreferrer">{item.url}</a> },
|
||||
{ label: '[en]PDF File[/en][ja]PDF ファイル[/ja]', value: <ItemTypeField.ItemFile lang={lang} file={item.file} type="book_pdf" downloadLimit={item.attachment_dl_limit} /> },
|
||||
{ label: 'Index', value: <ItemTypeField.ItemIndex lang={lang} index={item.index} /> },
|
||||
{ label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} /> },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export default BookDetail;
|
||||
@@ -0,0 +1,31 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Functions from '../../../functions';
|
||||
import iconFile from '../../assets/images/icon_book.gif';
|
||||
import { ItemBook } from '../../lib/ItemUtil';
|
||||
import ListBase, { ListBaseProps } from '../lib/ListBase';
|
||||
|
||||
class BookList extends ListBase {
|
||||
|
||||
constructor(props: ListBaseProps) {
|
||||
super(props);
|
||||
this.label = 'Book';
|
||||
this.icon = iconFile;
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemBook;
|
||||
const authors = item.author.map((author, i) => {
|
||||
return <Fragment key={i}>{i > 0 && ', '}{Functions.mlang(author, lang)}</Fragment>
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link><br />
|
||||
{authors}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default BookList;
|
||||
@@ -0,0 +1,15 @@
|
||||
import TopBase, { TopBaseProps } from '../lib/TopBase';
|
||||
import iconFile from '../../assets/images/icon_book.gif';
|
||||
|
||||
class BookTop extends TopBase {
|
||||
|
||||
constructor(props: TopBaseProps) {
|
||||
super(props);
|
||||
this.type = 'book';
|
||||
this.label = 'Book';
|
||||
this.icon = iconFile;
|
||||
this.description = '[en]Related book collection.[/en][ja]関連書籍[/ja]';
|
||||
}
|
||||
}
|
||||
|
||||
export default BookTop;
|
||||
@@ -0,0 +1,13 @@
|
||||
import BookTop from './BookTop';
|
||||
import BookList from './BookList';
|
||||
import BookDetail from './BookDetail';
|
||||
import BookAdvancedSearch from './BookAdvancedSearch';
|
||||
|
||||
const ItemTypeBook = {
|
||||
Top: BookTop,
|
||||
List: BookList,
|
||||
Detail: BookDetail,
|
||||
AdvancedSearch: BookAdvancedSearch,
|
||||
};
|
||||
|
||||
export default ItemTypeBook;
|
||||
@@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import { ItemConferenceSubTypes } from '../../lib/ItemUtil';
|
||||
import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
|
||||
|
||||
class ConferenceAdvancedSearch extends AdvancedSearchBase {
|
||||
|
||||
constructor(props: AdvancedSearchBaseProps) {
|
||||
super(props);
|
||||
this.type = 'conference';
|
||||
this.title = 'Conference';
|
||||
const now = new Date();
|
||||
const year = String(now.getFullYear());
|
||||
const month = String(now.getMonth() + 1);
|
||||
const mday = String(now.getDate());
|
||||
this.state.values['title'] = '';
|
||||
this.state.values['presentation_type'] = '';
|
||||
this.state.values['author'] = '';
|
||||
this.state.values['conference_from_year'] = year;
|
||||
this.state.values['conference_from_month'] = month;
|
||||
this.state.values['conference_from_mday'] = mday;
|
||||
this.state.values['conference_to_year'] = year;
|
||||
this.state.values['conference_to_month'] = month;
|
||||
this.state.values['conference_to_mday'] = mday;
|
||||
this.setIgnoreKey('conference_from_year');
|
||||
this.setIgnoreKey('conference_from_month');
|
||||
this.setIgnoreKey('conference_from_mday');
|
||||
this.setIgnoreKey('conference_to_year');
|
||||
this.setIgnoreKey('conference_to_month');
|
||||
this.setIgnoreKey('conference_to_mday');
|
||||
}
|
||||
|
||||
renderDate() {
|
||||
return (
|
||||
<>
|
||||
<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() {
|
||||
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]Author[/en][ja]発表者[/ja]', value: this.renderFieldInputText('author', 50) },
|
||||
{ label: '[en]Date[/en][ja]日付[/ja]', value: this.renderDate() }
|
||||
];
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
export default ConferenceAdvancedSearch;
|
||||
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import Functions from '../../../functions';
|
||||
import { ItemConference } from '../../lib/ItemUtil';
|
||||
import DetailBase from '../lib/DetailBase';
|
||||
import ItemTypeField from '../lib/field';
|
||||
import ConferenceUtil from './ConferenceUtil';
|
||||
|
||||
class ConferenceDetail extends DetailBase {
|
||||
|
||||
getFields() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemConference;
|
||||
return [
|
||||
{ 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]Place[/en][ja]開催地[/ja]', value: item.place },
|
||||
{ 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]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]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} type="conference_file" /> },
|
||||
{ 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} type="conference_paper" /> },
|
||||
{ label: 'Index', value: <ItemTypeField.ItemIndex lang={lang} index={item.index} /> },
|
||||
{ label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} /> },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export default ConferenceDetail;
|
||||
@@ -0,0 +1,33 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ItemConference } from '../../lib/ItemUtil';
|
||||
import ListBase, { ListBaseProps } from '../lib/ListBase';
|
||||
import ConferenceUtil from './ConferenceUtil';
|
||||
import iconFile from '../../assets/images/icon_conference.gif';
|
||||
import Functions from '../../../functions';
|
||||
|
||||
class ConferenceList extends ListBase {
|
||||
|
||||
constructor(props: ListBaseProps) {
|
||||
super(props);
|
||||
this.label = 'Conference';
|
||||
this.icon = iconFile;
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemConference;
|
||||
const authors = item.author.map((author, i) => {
|
||||
return <Fragment key={i}>{i > 0 && ', '}{Functions.mlang(author, lang)}</Fragment>
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link><br />
|
||||
{Functions.mlang(item.conference_title, lang)} (<ConferenceUtil.PresentationType lang={lang} type={item.presentation_type} />)<br />
|
||||
{authors}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ConferenceList;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { ItemConferenceSubTypes } from '../../lib/ItemUtil';
|
||||
import TopBase, { TopBaseProps } from '../lib/TopBase';
|
||||
import iconFile from '../../assets/images/icon_conference.gif';
|
||||
|
||||
class ConferenceTop extends TopBase {
|
||||
|
||||
constructor(props: TopBaseProps) {
|
||||
super(props);
|
||||
this.type = 'conference';
|
||||
this.label = 'Conference';
|
||||
this.icon = iconFile;
|
||||
this.description = '[en]Electrical presentation files for conference.[/en][ja]学会発表[/ja]';
|
||||
this.subTypes = ItemConferenceSubTypes;
|
||||
}
|
||||
}
|
||||
|
||||
export default ConferenceTop;
|
||||
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../config';
|
||||
import { ItemConference, ItemConferenceSubType, ItemConferenceSubTypes } from '../../lib/ItemUtil';
|
||||
|
||||
interface PresentationTypeProps {
|
||||
lang: MultiLang;
|
||||
type: ItemConferenceSubType;
|
||||
}
|
||||
|
||||
const PresentationType = (props: PresentationTypeProps) => {
|
||||
const { type } = props;
|
||||
const subtype = ItemConferenceSubTypes.find((value) => { return value.type === type; });
|
||||
if (typeof subtype === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
return (<span>{subtype.label}</span>);
|
||||
}
|
||||
|
||||
interface ConferenceDateProps {
|
||||
lang: MultiLang;
|
||||
item: ItemConference;
|
||||
}
|
||||
|
||||
const ConferenceDate = (props: ConferenceDateProps) => {
|
||||
const { item } = props;
|
||||
const monthStr = ['Jan', '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 (<span>{from} {to}</span>);
|
||||
}
|
||||
|
||||
const ConferenceUtil = {
|
||||
PresentationType,
|
||||
ConferenceDate,
|
||||
}
|
||||
|
||||
export default ConferenceUtil;
|
||||
@@ -0,0 +1,13 @@
|
||||
import ConferenceTop from './ConferenceTop';
|
||||
import ConferenceList from './ConferenceList';
|
||||
import ConferenceDetail from './ConferenceDetail';
|
||||
import ConferenceAdvancedSearch from './ConferenceAdvancedSearch';
|
||||
|
||||
const ItemTypeConference = {
|
||||
Top: ConferenceTop,
|
||||
List: ConferenceList,
|
||||
Detail: ConferenceDetail,
|
||||
AdvancedSearch: ConferenceAdvancedSearch,
|
||||
};
|
||||
|
||||
export default ItemTypeConference;
|
||||
@@ -0,0 +1,46 @@
|
||||
import { ItemDataSubTypes } from '../../lib/ItemUtil';
|
||||
import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
|
||||
|
||||
class DataAdvancedSearch extends AdvancedSearchBase {
|
||||
|
||||
constructor(props: AdvancedSearchBaseProps) {
|
||||
super(props);
|
||||
this.type = 'data';
|
||||
this.title = 'Data';
|
||||
const now = new Date();
|
||||
const year = String(now.getFullYear());
|
||||
const month = String(now.getMonth() + 1);
|
||||
const mday = String(now.getDate());
|
||||
this.state.values['title'] = '';
|
||||
this.state.values['keyword'] = '';
|
||||
this.state.values['description'] = '';
|
||||
this.state.values['doi'] = '';
|
||||
this.state.values['data_type'] = '';
|
||||
this.state.values['experimenter'] = '';
|
||||
this.state.values['publication_year'] = year;
|
||||
this.state.values['publication_month'] = month;
|
||||
this.state.values['publication_mday'] = mday;
|
||||
this.state.values['file.preview.caption'] = '';
|
||||
this.state.values['file.data_file.original_file_name'] = '';
|
||||
this.setIgnoreKey('publication_year');
|
||||
this.setIgnoreKey('publication_month');
|
||||
this.setIgnoreKey('publication_mday');
|
||||
}
|
||||
|
||||
getRows() {
|
||||
const rows = [
|
||||
{ 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: '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;
|
||||
}
|
||||
}
|
||||
|
||||
export default DataAdvancedSearch;
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import Functions from '../../../functions';
|
||||
import ItemUtil, { ItemData } from '../../lib/ItemUtil';
|
||||
import DetailBase from '../lib/DetailBase';
|
||||
import ItemTypeField from '../lib/field';
|
||||
import SimPFLinkIcon from '../lib/field/SimPFLinkIcon';
|
||||
import DataUtil from './DataUtil';
|
||||
|
||||
class DataDetail extends DetailBase {
|
||||
|
||||
getFields() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemData;
|
||||
const fields = [
|
||||
{ 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]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]Date[/en][ja]日付[/ja]', value: <ItemTypeField.PublicationDate 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.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]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} /> },
|
||||
{ label: '[en]Data File[/en][ja]データファイル[/ja]', value: <ItemTypeField.ItemFile lang={lang} file={item.file} type="data_file" rights={item.rights} useCc={item.use_cc} ccCommercialUse={item.cc_commercial_use} ccModification={item.cc_modification} downloadLimit={item.attachment_dl_limit} /> },
|
||||
{ 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} /> },
|
||||
{ label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} /> },
|
||||
];
|
||||
const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id);
|
||||
if (simpfLinkUrl !== '') {
|
||||
const field = { label: 'Online Simulation', value: <SimPFLinkIcon lang={lang} url={simpfLinkUrl} isDetail={true} /> };
|
||||
fields.splice(14, 0, field);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
||||
export default DataDetail;
|
||||
@@ -0,0 +1,31 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Functions from '../../../functions';
|
||||
import iconFile from '../../assets/images/icon_data.gif';
|
||||
import { ItemData } from '../../lib/ItemUtil';
|
||||
import ListBase, { ListBaseProps } from '../lib/ListBase';
|
||||
|
||||
class DataList extends ListBase {
|
||||
|
||||
constructor(props: ListBaseProps) {
|
||||
super(props);
|
||||
this.label = 'Data';
|
||||
this.icon = iconFile;
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemData;
|
||||
const authors = item.experimenter.map((author, i) => {
|
||||
return <Fragment key={i}>{i > 0 && ', '}{Functions.mlang(author, lang)}</Fragment>
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link><br />
|
||||
{authors}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DataList;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { ItemDataSubTypes } from '../../lib/ItemUtil';
|
||||
import TopBase, { TopBaseProps } from '../lib/TopBase';
|
||||
import iconFile from '../../assets/images/icon_data.gif';
|
||||
|
||||
class DataTop extends TopBase {
|
||||
|
||||
constructor(props: TopBaseProps) {
|
||||
super(props);
|
||||
this.type = 'data';
|
||||
this.label = 'Data';
|
||||
this.icon = iconFile;
|
||||
this.description = '[en]Result data in numerical text/image/movie formats.[/en][ja]実験結果の数値データ/画像/動画など[/ja]';
|
||||
this.subTypes = ItemDataSubTypes;
|
||||
}
|
||||
}
|
||||
|
||||
export default DataTop;
|
||||
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../config';
|
||||
import { ItemDataSubType, ItemDataSubTypes } from '../../lib/ItemUtil';
|
||||
|
||||
interface DataTypeProps {
|
||||
lang: MultiLang;
|
||||
type: ItemDataSubType;
|
||||
}
|
||||
|
||||
const DataType = (props: DataTypeProps) => {
|
||||
const { type } = props;
|
||||
const subtype = ItemDataSubTypes.find((value) => { return value.type === type; });
|
||||
if (typeof subtype === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
return (<span>{subtype.label}</span>);
|
||||
}
|
||||
|
||||
const DataUtil = {
|
||||
DataType,
|
||||
}
|
||||
|
||||
export default DataUtil;
|
||||
@@ -0,0 +1,13 @@
|
||||
import DataTop from './DataTop';
|
||||
import DataList from './DataList';
|
||||
import DataDetail from './DataDetail';
|
||||
import DataAdvancedSearch from './DataAdvancedSearch';
|
||||
|
||||
const ItemTypeData = {
|
||||
Top: DataTop,
|
||||
List: DataList,
|
||||
Detail: DataDetail,
|
||||
AdvancedSearch: DataAdvancedSearch,
|
||||
};
|
||||
|
||||
export default ItemTypeData;
|
||||
@@ -0,0 +1,30 @@
|
||||
import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
|
||||
|
||||
class FilesAdvancedSearch extends AdvancedSearchBase {
|
||||
|
||||
constructor(props: AdvancedSearchBaseProps) {
|
||||
super(props);
|
||||
this.type = 'files';
|
||||
this.title = 'Files';
|
||||
this.state.values['title'] = '';
|
||||
this.state.values['data_file_name'] = '';
|
||||
this.state.values['data_file_mimetype'] = '';
|
||||
this.state.values['data_file_filetype'] = '';
|
||||
this.state.values['keyword'] = '';
|
||||
this.state.values['description'] = '';
|
||||
}
|
||||
|
||||
getRows() {
|
||||
const rows = [
|
||||
{ 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 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;
|
||||
}
|
||||
}
|
||||
|
||||
export default FilesAdvancedSearch;
|
||||
@@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import Functions from '../../../functions';
|
||||
import { ItemFiles } from '../../lib/ItemUtil';
|
||||
import DetailBase from '../lib/DetailBase';
|
||||
import ItemTypeField from '../lib/field';
|
||||
|
||||
class FilesDetail extends DetailBase {
|
||||
|
||||
getFields() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemFiles;
|
||||
return [
|
||||
{ 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]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]Data File[/en][ja]データファイル[/ja]', value: <ItemTypeField.ItemFile lang={lang} file={item.file} type="files_file" /> },
|
||||
{ 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} /> },
|
||||
{ label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} /> },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export default FilesDetail;
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Functions from '../../../functions';
|
||||
import iconFile from '../../assets/images/icon_files.gif';
|
||||
import { ItemFiles } from '../../lib/ItemUtil';
|
||||
import Contributer from '../lib/field/Contributer';
|
||||
import ListBase, { ListBaseProps } from '../lib/ListBase';
|
||||
|
||||
class FilesList extends ListBase {
|
||||
|
||||
constructor(props: ListBaseProps) {
|
||||
super(props);
|
||||
this.label = 'Files';
|
||||
this.icon = iconFile;
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemFiles;
|
||||
return (
|
||||
<>
|
||||
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link><br />
|
||||
<Contributer lang={lang} uname={item.uname} name={item.name} /><br />
|
||||
{item.data_file_mimetype}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default FilesList;
|
||||
@@ -0,0 +1,17 @@
|
||||
import TopBase, { TopBaseProps } from '../lib/TopBase';
|
||||
import iconFile from '../../assets/images/icon_files.gif';
|
||||
import { ItemFilesSubTypes } from '../../lib/ItemUtil';
|
||||
|
||||
class FilesTop extends TopBase {
|
||||
|
||||
constructor(props: TopBaseProps) {
|
||||
super(props);
|
||||
this.type = 'files';
|
||||
this.label = 'Files';
|
||||
this.icon = iconFile;
|
||||
this.description = '[en]Various type of File.[/en][ja]ファイル[/ja]';
|
||||
this.subTypes = ItemFilesSubTypes;
|
||||
}
|
||||
}
|
||||
|
||||
export default FilesTop;
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
const FilesUtil = {
|
||||
}
|
||||
|
||||
export default FilesUtil;
|
||||
@@ -0,0 +1,13 @@
|
||||
import FilesTop from './FilesTop';
|
||||
import FilesList from './FilesList';
|
||||
import FilesDetail from './FilesDetail';
|
||||
import FilesAdvancedSearch from './FilesAdvancedSearch';
|
||||
|
||||
const ItemTypeFiles = {
|
||||
Top: FilesTop,
|
||||
List: FilesList,
|
||||
Detail: FilesDetail,
|
||||
AdvancedSearch: FilesAdvancedSearch,
|
||||
};
|
||||
|
||||
export default ItemTypeFiles;
|
||||
@@ -0,0 +1,179 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../config';
|
||||
import AdvancedSearchQuery from '../lib/AdvancedSearchQuery';
|
||||
import { Item, ItemBinder, ItemBook, ItemConference, ItemData, ItemFiles, ItemModel, ItemPaper, ItemPresentation, ItemSimulator, ItemStimulus, ItemTool, ItemUrl, ItemMemo } from '../lib/ItemUtil';
|
||||
import ItemTypeBinder from './binder';
|
||||
import ItemTypeBook from './book';
|
||||
import ItemTypeConference from './conference';
|
||||
import ItemTypeData from './data';
|
||||
import ItemTypeFiles from './files';
|
||||
import ItemTypeMemo from './memo';
|
||||
import ItemTypeModel from './model';
|
||||
import ItemTypePaper from './paper';
|
||||
import ItemTypePresentation from './presentation';
|
||||
import ItemTypeSimulator from './simulator';
|
||||
import ItemTypeStimulus from './stimulus';
|
||||
import ItemTypeTool from './tool';
|
||||
import ItemTypeUrl from './url';
|
||||
|
||||
interface TopProps {
|
||||
lang: MultiLang;
|
||||
type: string;
|
||||
}
|
||||
const Top = (props: TopProps) => {
|
||||
const { lang, type } = props;
|
||||
switch (type) {
|
||||
case 'xnpbinder':
|
||||
return <ItemTypeBinder.Top lang={lang} />;
|
||||
case 'xnpbook':
|
||||
return <ItemTypeBook.Top lang={lang} />;
|
||||
case 'xnpconference':
|
||||
return <ItemTypeConference.Top lang={lang} />;
|
||||
case 'xnpdata':
|
||||
return <ItemTypeData.Top lang={lang} />;
|
||||
case 'xnpfiles':
|
||||
return <ItemTypeFiles.Top lang={lang} />;
|
||||
case 'xnpmemo':
|
||||
return <ItemTypeMemo.Top lang={lang} />;
|
||||
case 'xnpmodel':
|
||||
return <ItemTypeModel.Top lang={lang} />;
|
||||
case 'xnppaper':
|
||||
return <ItemTypePaper.Top lang={lang} />;
|
||||
case 'xnppresentation':
|
||||
return <ItemTypePresentation.Top lang={lang} />;
|
||||
case 'xnpsimulator':
|
||||
return <ItemTypeSimulator.Top lang={lang} />;
|
||||
case 'xnpstimulus':
|
||||
return <ItemTypeStimulus.Top lang={lang} />;
|
||||
case 'xnptool':
|
||||
return <ItemTypeTool.Top lang={lang} />;
|
||||
case 'xnpurl':
|
||||
return <ItemTypeUrl.Top lang={lang} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
interface ListProps {
|
||||
lang: MultiLang;
|
||||
item: Item;
|
||||
}
|
||||
const List = (props: ListProps) => {
|
||||
const { lang, item } = props;
|
||||
switch (item.item_type_name) {
|
||||
case 'xnpbinder':
|
||||
return <ItemTypeBinder.List lang={lang} item={item as ItemBinder} />;
|
||||
case 'xnpbook':
|
||||
return <ItemTypeBook.List lang={lang} item={item as ItemBook} />;
|
||||
case 'xnpconference':
|
||||
return <ItemTypeConference.List lang={lang} item={item as ItemConference} />;
|
||||
case 'xnpdata':
|
||||
return <ItemTypeData.List lang={lang} item={item as ItemData} />;
|
||||
case 'xnpfiles':
|
||||
return <ItemTypeFiles.List lang={lang} item={item as ItemFiles} />;
|
||||
case 'xnpmemo':
|
||||
return <ItemTypeMemo.List lang={lang} item={item as ItemMemo} />;
|
||||
case 'xnpmodel':
|
||||
return <ItemTypeModel.List lang={lang} item={item as ItemModel} />;
|
||||
case 'xnppaper':
|
||||
return <ItemTypePaper.List lang={lang} item={item as ItemPaper} />;
|
||||
case 'xnppresentation':
|
||||
return <ItemTypePresentation.List lang={lang} item={item as ItemPresentation} />;
|
||||
case 'xnpsimulator':
|
||||
return <ItemTypeSimulator.List lang={lang} item={item as ItemSimulator} />;
|
||||
case 'xnpstimulus':
|
||||
return <ItemTypeStimulus.List lang={lang} item={item as ItemStimulus} />;
|
||||
case 'xnptool':
|
||||
return <ItemTypeTool.List lang={lang} item={item as ItemTool} />;
|
||||
case 'xnpurl':
|
||||
return <ItemTypeUrl.List lang={lang} item={item as ItemUrl} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
interface DetailProps {
|
||||
lang: MultiLang;
|
||||
item: Item;
|
||||
}
|
||||
const Detail = (props: DetailProps) => {
|
||||
const { lang, item } = props;
|
||||
switch (item.item_type_name) {
|
||||
case 'xnpbinder':
|
||||
return <ItemTypeBinder.Detail lang={lang} item={item as ItemBinder} />;
|
||||
case 'xnpbook':
|
||||
return <ItemTypeBook.Detail lang={lang} item={item as ItemBook} />;
|
||||
case 'xnpconference':
|
||||
return <ItemTypeConference.Detail lang={lang} item={item as ItemConference} />;
|
||||
case 'xnpdata':
|
||||
return <ItemTypeData.Detail lang={lang} item={item as ItemData} />;
|
||||
case 'xnpfiles':
|
||||
return <ItemTypeFiles.Detail lang={lang} item={item as ItemFiles} />;
|
||||
case 'xnpmemo':
|
||||
return <ItemTypeMemo.Detail lang={lang} item={item as ItemMemo} />;
|
||||
case 'xnpmodel':
|
||||
return <ItemTypeModel.Detail lang={lang} item={item as ItemModel} />;
|
||||
case 'xnppaper':
|
||||
return <ItemTypePaper.Detail lang={lang} item={item as ItemPaper} />;
|
||||
case 'xnppresentation':
|
||||
return <ItemTypePresentation.Detail lang={lang} item={item as ItemPresentation} />;
|
||||
case 'xnpsimulator':
|
||||
return <ItemTypeSimulator.Detail lang={lang} item={item as ItemSimulator} />;
|
||||
case 'xnpstimulus':
|
||||
return <ItemTypeStimulus.Detail lang={lang} item={item as ItemStimulus} />;
|
||||
case 'xnptool':
|
||||
return <ItemTypeTool.Detail lang={lang} item={item as ItemTool} />;
|
||||
case 'xnpurl':
|
||||
return <ItemTypeUrl.Detail lang={lang} item={item as ItemUrl} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
interface AdvancedSearchProps {
|
||||
lang: MultiLang;
|
||||
type: string;
|
||||
query: AdvancedSearchQuery;
|
||||
}
|
||||
const AdvancedSearch = (props: AdvancedSearchProps) => {
|
||||
const { lang, type, query } = props;
|
||||
switch (type) {
|
||||
case 'xnpbinder':
|
||||
return <ItemTypeBinder.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpbook':
|
||||
return <ItemTypeBook.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpconference':
|
||||
return <ItemTypeConference.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpdata':
|
||||
return <ItemTypeData.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpfiles':
|
||||
return <ItemTypeFiles.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpmemo':
|
||||
return <ItemTypeMemo.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpmodel':
|
||||
return <ItemTypeModel.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnppaper':
|
||||
return <ItemTypePaper.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnppresentation':
|
||||
return <ItemTypePresentation.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpsimulator':
|
||||
return <ItemTypeSimulator.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpstimulus':
|
||||
return <ItemTypeStimulus.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnptool':
|
||||
return <ItemTypeTool.AdvancedSearch lang={lang} query={query} />;
|
||||
case 'xnpurl':
|
||||
return <ItemTypeUrl.AdvancedSearch lang={lang} query={query} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const ItemType = {
|
||||
Top,
|
||||
List,
|
||||
Detail,
|
||||
AdvancedSearch
|
||||
}
|
||||
|
||||
export default ItemType;
|
||||
@@ -0,0 +1,189 @@
|
||||
import React, { ChangeEvent, Component } from 'react';
|
||||
import { MultiLang } from '../../../config';
|
||||
import Functions from '../../../functions';
|
||||
import AdvancedSearchQuery from '../../lib/AdvancedSearchQuery';
|
||||
import { ItemSubTypes } from '../../lib/ItemUtil';
|
||||
|
||||
export interface AdvancedSearchBaseProps {
|
||||
lang: MultiLang;
|
||||
query: AdvancedSearchQuery;
|
||||
}
|
||||
|
||||
interface State {
|
||||
show: boolean;
|
||||
values: any;
|
||||
}
|
||||
|
||||
class AdvancedSearchBase extends Component<AdvancedSearchBaseProps, State> {
|
||||
|
||||
protected type: string = 'base'
|
||||
protected title: string = 'Base';
|
||||
protected query: AdvancedSearchQuery;
|
||||
protected ignoreKeys: string[] = [];
|
||||
|
||||
constructor(props: AdvancedSearchBaseProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
show: false,
|
||||
values: {},
|
||||
}
|
||||
this.query = props.query;
|
||||
this.handleChangeTitleCheck = this.handleChangeTitleCheck.bind(this);
|
||||
}
|
||||
|
||||
updateQuery(key: string, value: string) {
|
||||
if (this.ignoreKeys.includes(key)) {
|
||||
this.query.delete(this.type, key);
|
||||
} else {
|
||||
this.query.set(this.type, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
setIgnoreKey(key: string) {
|
||||
if (!this.ignoreKeys.includes(key)) {
|
||||
this.ignoreKeys = this.ignoreKeys.concat(key);
|
||||
}
|
||||
this.query.delete(this.type, key);
|
||||
}
|
||||
|
||||
deleteIgnoreKey(key: string) {
|
||||
if (this.ignoreKeys.includes(key)) {
|
||||
this.ignoreKeys = this.ignoreKeys.filter((v) => {
|
||||
return (v !== key);
|
||||
});
|
||||
}
|
||||
this.query.set(this.type, key, this.state.values[key]);
|
||||
}
|
||||
|
||||
updateField(key: string, value: string) {
|
||||
let values = Object.assign({}, this.state.values);
|
||||
values[key] = value;
|
||||
this.updateQuery(key, value);
|
||||
this.setState({ values });
|
||||
}
|
||||
|
||||
handleChangeTitleCheck(e: ChangeEvent<HTMLInputElement>) {
|
||||
const show = e.target.checked;
|
||||
if (show) {
|
||||
Object.keys(this.state.values).forEach((key) => {
|
||||
const value = this.state.values[key];
|
||||
this.updateQuery(key, value);
|
||||
});
|
||||
} else {
|
||||
this.query.deleteType(this.type);
|
||||
}
|
||||
this.setState({ show });
|
||||
}
|
||||
|
||||
getRows(): { label: string, value: JSX.Element }[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
renderFieldInputText(key: string, size: number) {
|
||||
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.updateField(key, e.target.value);
|
||||
};
|
||||
return (
|
||||
<input className="fieldInputText" type="text" value={this.state.values[key]} size={size} onChange={onChange} />
|
||||
);
|
||||
}
|
||||
|
||||
renderFieldSelect(key: string, values: ItemSubTypes<any>) {
|
||||
const onChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
this.updateField(key, e.target.value);
|
||||
};
|
||||
const options = values.map(({ type, label }, i) => {
|
||||
return <option key={i} value={type}>{label}</option>;
|
||||
});
|
||||
return (
|
||||
<select className="fieldSelect" value={this.state.values[key]} onChange={onChange}>
|
||||
<option value=''>Any</option>
|
||||
{options}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
||||
renderFieldDate(label: string, keyYear: string, keyMonth: string, keyMday: string) {
|
||||
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.checked) {
|
||||
this.deleteIgnoreKey(keyYear);
|
||||
keyMonth !== '' && this.deleteIgnoreKey(keyMonth);
|
||||
keyMday !== '' && this.deleteIgnoreKey(keyMday);
|
||||
} else {
|
||||
this.setIgnoreKey(keyYear);
|
||||
keyMonth !== '' && this.setIgnoreKey(keyMonth);
|
||||
keyMday !== '' && this.setIgnoreKey(keyMday);
|
||||
}
|
||||
};
|
||||
const month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
const monthOptions = month.map((value, i) => {
|
||||
return <option key={i} value={i + 1}>{value}</option>;
|
||||
})
|
||||
let mdayOptions: JSX.Element[] = [];
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
mdayOptions.push(<option key={i} value={i}>{i}</option>)
|
||||
}
|
||||
return (
|
||||
<div className="fieldDate">
|
||||
<input type="checkbox" onChange={onChange} />
|
||||
{label.length !== 0 && <label className="fieldDateLabel">{label}</label>}
|
||||
{keyMonth !== '' &&
|
||||
<select value={this.state.values[keyMonth]} onChange={(e) => this.updateField(keyMonth, e.target.value)}>
|
||||
{monthOptions}
|
||||
</select>
|
||||
}
|
||||
{keyMday !== '' &&
|
||||
<select value={this.state.values[keyMday]} onChange={(e) => this.updateField(keyMday, e.target.value)}>
|
||||
{mdayOptions}
|
||||
</select>
|
||||
}
|
||||
<input type="text" value={this.state.values[keyYear]} size={5} onChange={(e) => this.updateField(keyYear, e.target.value)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { lang } = this.props;
|
||||
if (this.state.show === false) {
|
||||
return null;
|
||||
}
|
||||
const rows = this.getRows();
|
||||
const fields = rows.map((value, idx) => {
|
||||
const evenodd = idx % 2 === 0 ? 'even' : 'odd';
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td className="head">{Functions.mlang(value.label, lang)}</td>
|
||||
<td className={evenodd}>{value.value}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<table className="itemtypeFields outer">
|
||||
<tbody>
|
||||
{fields}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="itemtype">
|
||||
<table className="itemtypeName outer">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th align="left">
|
||||
<input type="checkbox" checked={this.state.show} onChange={this.handleChangeTitleCheck} />
|
||||
{this.title}
|
||||
</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{this.renderBody()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AdvancedSearchBase;
|
||||
@@ -0,0 +1,43 @@
|
||||
import React, { Component, ReactNode } from 'react';
|
||||
import { MultiLang } from '../../../config';
|
||||
import Functions from '../../../functions';
|
||||
import { Item } from '../../lib/ItemUtil';
|
||||
|
||||
export interface DetailBaseField {
|
||||
label: string;
|
||||
value: ReactNode;
|
||||
}
|
||||
|
||||
export interface DetailBaseProps {
|
||||
lang: MultiLang;
|
||||
item: Item
|
||||
}
|
||||
|
||||
class DetailBase extends Component<DetailBaseProps> {
|
||||
|
||||
getFields(): DetailBaseField[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const elements = this.getFields().map((value, idx) => {
|
||||
const evenodd = idx % 2 === 0 ? 'even' : 'odd';
|
||||
return (
|
||||
<tr key={idx}>
|
||||
<td className="head">{Functions.mlang(value.label, lang)}</td>
|
||||
<td className={evenodd}>{value.value}</td>
|
||||
</tr>
|
||||
)
|
||||
});
|
||||
return (
|
||||
<table className="outer itemDetail">
|
||||
<tbody>
|
||||
{elements}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DetailBase;
|
||||
@@ -0,0 +1,50 @@
|
||||
import React, { Component } from 'react';
|
||||
import { MultiLang } from '../../../config';
|
||||
import ItemUtil, { Item } from '../../lib/ItemUtil';
|
||||
import SimPFLinkIcon from './field/SimPFLinkIcon';
|
||||
|
||||
export interface ListBaseProps {
|
||||
lang: MultiLang;
|
||||
item: Item
|
||||
};
|
||||
|
||||
class ListBase extends Component<ListBaseProps> {
|
||||
|
||||
protected label = '';
|
||||
protected icon = '';
|
||||
protected url: string;
|
||||
protected simpfLinkUrl: string;
|
||||
|
||||
constructor(props: ListBaseProps) {
|
||||
super(props);
|
||||
this.url = ItemUtil.getUrl(props.item);
|
||||
this.simpfLinkUrl = ItemUtil.getSimPFLinkUrl(props.item.item_id);
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
return (
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="listIcon">
|
||||
<img src={this.icon} alt={this.label} />
|
||||
</td>
|
||||
<td>
|
||||
{this.renderBody()}
|
||||
</td>
|
||||
<td className="listExtra">
|
||||
<SimPFLinkIcon lang={lang} url={this.simpfLinkUrl} isDetail={false} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ListBase;
|
||||
@@ -0,0 +1,47 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { MultiLang } from '../../../config';
|
||||
import Functions from '../../../functions';
|
||||
import ItemUtil, { ItemSubTypes } from '../../lib/ItemUtil';
|
||||
|
||||
export interface TopBaseProps {
|
||||
lang: MultiLang;
|
||||
}
|
||||
|
||||
class TopBase extends Component<TopBaseProps> {
|
||||
|
||||
protected type: string = '';
|
||||
protected label: string = '';
|
||||
protected icon: string = '';
|
||||
protected description: string = '';
|
||||
protected subTypes: ItemSubTypes<any> = [];
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const url = ItemUtil.getItemTypeSearchUrl(this.type);
|
||||
const links = this.subTypes.map(({ type, label }, i) => {
|
||||
return <Fragment key={i}>{i > 0 && ' / '}<Link to={url + '/' + type}>{label}</Link></Fragment>;
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<img src={this.icon} alt={this.label} />
|
||||
</td>
|
||||
<td className="itemTypeName">
|
||||
<Link to={url}>{this.label}</Link>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<div>{Functions.mlang(this.description, lang)}</div>
|
||||
{links}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TopBase;
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
author: string[];
|
||||
}
|
||||
|
||||
const Author = (props: Props) => {
|
||||
const { author } = props;
|
||||
if (author.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const elements = author.map((value, idx) => {
|
||||
const evenodd = idx % 2 === 0 ? 'even' : 'odd';
|
||||
return <tr key={idx}><td className={evenodd}>{value}</td></tr>;
|
||||
});
|
||||
return <table><tbody>{elements}</tbody></table>;
|
||||
}
|
||||
|
||||
export default Author;
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import Functions from '../../../../functions';
|
||||
import { ItemBasicChangeLog } from '../../../lib/ItemUtil';
|
||||
import DateTime from './DateTime';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
changelog: ItemBasicChangeLog[];
|
||||
}
|
||||
|
||||
const ChangeLog = (props: Props) => {
|
||||
const { lang, changelog } = props;
|
||||
if (changelog.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const elements = changelog.map((value, i) => {
|
||||
return (
|
||||
<tr key={i}>
|
||||
<td><DateTime lang={lang} date={value.log_date} onlyDate={true} /></td>
|
||||
<td>{Functions.mlang(value.log, lang)}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
return (<table><tbody>{elements}</tbody></table>);
|
||||
}
|
||||
|
||||
export default ChangeLog;
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import Functions from '../../../../functions';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
uname: string;
|
||||
name: string
|
||||
}
|
||||
|
||||
const Contributer = (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;
|
||||
@@ -0,0 +1,56 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
|
||||
export type CreativeCommonsType = 'by' | 'by-nc' | 'by-nc-nd' | 'by-nc-sa' | 'by-nd' | 'by-sa';
|
||||
|
||||
export const getCreativeCommonsType = (ccCommercialUse: number, ccModification: number): CreativeCommonsType => {
|
||||
const cc = ccCommercialUse * 10 + ccModification;
|
||||
switch (cc) {
|
||||
case 0:
|
||||
return 'by-nc-nd';
|
||||
case 1:
|
||||
return 'by-nc-sa';
|
||||
case 2:
|
||||
return 'by-nc';
|
||||
case 10:
|
||||
return 'by-nd';
|
||||
case 11:
|
||||
return 'by-sa';
|
||||
case 12:
|
||||
default:
|
||||
return 'by';
|
||||
}
|
||||
}
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
type: CreativeCommonsType;
|
||||
}
|
||||
|
||||
const CreativeCommons = (props: Props) => {
|
||||
const { type } = props;
|
||||
const url = 'http://creativecommons.org/licenses/' + type + '/4.0/';
|
||||
const logoUrl = 'https://i.creativecommons.org/l/' + type + '/4.0/88x31.png';
|
||||
const labels = {
|
||||
by: 'Attribution',
|
||||
nc: 'NonCommercial',
|
||||
nd: 'NoDerivatives',
|
||||
sa: 'ShareAlike',
|
||||
}
|
||||
const label = type.split('-').map((value) => {
|
||||
const prop = value as 'by' | 'nc' | 'nd' | 'sa';
|
||||
return labels[prop];
|
||||
}).join('-');
|
||||
return (
|
||||
<table style={{borderCollapse: 'separate', borderSpacing: '5px'}}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href={url} target="_blank" rel="license noopener noreferrer"><img alt="Creative Commons License" src={logoUrl} /></a></td>
|
||||
<td>This work is licensed under a <a href={url} target="_blank" rel="license noopener noreferrer">Criative Commons {label} 4.0 International License</a>.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
export default CreativeCommons;
|
||||
@@ -0,0 +1,21 @@
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
date: number;
|
||||
onlyDate?: boolean
|
||||
}
|
||||
|
||||
const DateTime = (props: Props) => {
|
||||
const { date, onlyDate } = props;
|
||||
const d = moment(new Date(date * 1000));
|
||||
let format = 'MMM D, Y';
|
||||
if (typeof onlyDate === 'undefined' || !onlyDate) {
|
||||
format += ' HH:mm:ss';
|
||||
}
|
||||
return <span>{d.format(format)}</span>;
|
||||
}
|
||||
|
||||
export default DateTime;
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import XoopsCode from '../../../../common/lib/XoopsCode';
|
||||
import { MultiLang } from '../../../../config';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
description: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const Description = (props: Props) => {
|
||||
const { lang, description, className } = props;
|
||||
const textarea = <XoopsCode lang={lang} text={description} dobr={true} />;
|
||||
const name = typeof className === 'undefined' ? 'description' : className;
|
||||
return (<div className={name}>{textarea}</div>);
|
||||
}
|
||||
|
||||
export default Description;
|
||||
@@ -0,0 +1,21 @@
|
||||
.downloadButton {
|
||||
display: inline-block;
|
||||
padding: 7px 20px;
|
||||
text-decoration: none !important;
|
||||
font-weight: normal !important;
|
||||
background: #f0f0f0;
|
||||
color: #000 !important;
|
||||
border: solid 1px #e0e0e0;
|
||||
box-shadow: 2px 2px #bbbbbb;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.downloadButton:hover {
|
||||
background: #e8e8e8 !important;
|
||||
border: solid 1px #cccccc;
|
||||
}
|
||||
|
||||
.downloadButton:active {
|
||||
transform: translate(2px, 2px);
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import React, { Component } from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil';
|
||||
import styles from './FileDownloadButton.module.css';
|
||||
import LicenseAgreementDialog from './LicenseAgreementDialog';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
file: ItemBasicFile;
|
||||
rights: string;
|
||||
useCc: number;
|
||||
ccCommercialUse: number;
|
||||
ccModification: number;
|
||||
}
|
||||
|
||||
interface State {
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
class FileDownloadButton extends Component<Props, State> {
|
||||
|
||||
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>) {
|
||||
if (this.props.rights !== '') {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.setState({ show: true });
|
||||
}
|
||||
}
|
||||
|
||||
unsetShow() {
|
||||
this.setState({ show: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang, file, rights, useCc, ccCommercialUse, ccModification } = this.props;
|
||||
const url = ItemUtil.getFileUrl(this.props.file);
|
||||
return (
|
||||
<>
|
||||
<a className={styles.downloadButton} href={url} download={file.original_file_name} target="_blank" rel="noopener noreferrer" onClick={this.handleClickDownload}>Download</a>
|
||||
<LicenseAgreementDialog lang={lang} file={file} rights={rights} useCc={useCc} ccCommercialUse={ccCommercialUse} ccModification={ccModification} show={this.state.show} unsetShow={this.unsetShow} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default FileDownloadButton;
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
size: number;
|
||||
}
|
||||
|
||||
const FileSize = (props: Props) => {
|
||||
const { size } = props;
|
||||
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 label = Math.round(size / Math.pow(1024, power) * 10) / 10 + ' ' + units[power]
|
||||
return <span>{label}</span>;
|
||||
}
|
||||
|
||||
export default FileSize;
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
keyword: string[];
|
||||
}
|
||||
|
||||
const FreeKeyword = (props: Props) => {
|
||||
const { keyword } = props;
|
||||
if (keyword.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const label = keyword.join(', ');
|
||||
return (<span>{label}</span>);
|
||||
}
|
||||
|
||||
export default FreeKeyword;
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import Functions from '../../../../functions';
|
||||
import { ItemBasicFile } from '../../../lib/ItemUtil';
|
||||
import DateTime from './DateTime';
|
||||
import FileDownloadButton from './FileDownloadButton';
|
||||
import FileSize from './FileSize';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
file: ItemBasicFile[];
|
||||
type: string;
|
||||
rights?: string;
|
||||
useCc?: number;
|
||||
ccCommercialUse?: number;
|
||||
ccModification?: number;
|
||||
downloadLimit?: number;
|
||||
}
|
||||
|
||||
const ItemFile = (props: Props) => {
|
||||
const { lang, file, type } = props;
|
||||
const rights = typeof props.rights === 'undefined' ? '' : props.rights;
|
||||
const useCc = typeof props.useCc === 'undefined' ? 0 : props.useCc;
|
||||
const ccCommercialUse = typeof props.ccCommercialUse === 'undefined' ? 0 : props.ccCommercialUse;
|
||||
const ccModification = typeof props.ccModification === 'undefined' ? 0 : props.ccModification;
|
||||
const downloadLimit = typeof props.downloadLimit === 'undefined' ? 0 : props.downloadLimit;
|
||||
const data = file.find((value) => {
|
||||
return value.file_type_name === type;
|
||||
});
|
||||
if (typeof data === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
const date = new Date(data.timestamp);
|
||||
const timestamp = Math.floor(date.valueOf() / 1000);
|
||||
return (
|
||||
<div>
|
||||
{data.original_file_name}<br />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td>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} />}</td></tr>
|
||||
<tr><td>Size</td><td>: <FileSize lang={lang} size={data.file_size} /></td></tr>
|
||||
<tr><td>Last updated</td><td>: <DateTime lang={lang} date={timestamp} onlyDate={true} /></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{downloadLimit === 1 && <><br />({Functions.mlang('[en]File has been removed[/en][ja]ファイルは削除されました[/ja]', lang)})</>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ItemFile;
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import Functions from '../../../../functions';
|
||||
import IndexUtil from '../../../lib/IndexUtil';
|
||||
import { ItemBasicIndex } from '../../../lib/ItemUtil';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
index: ItemBasicIndex[];
|
||||
}
|
||||
|
||||
const ItemIndex = (props: Props) => {
|
||||
const { lang, index } = props;
|
||||
if (index.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const elements = index.map((value, idx) => {
|
||||
const evenodd = idx % 2 === 0 ? 'even' : 'odd';
|
||||
const url = IndexUtil.getUrl(value.index_id);
|
||||
return (<tr key={value.index_id}><td className={evenodd}><Link to={url}>{Functions.mlang(value.title, lang)}</Link></td></tr>);
|
||||
});
|
||||
return (<table><tbody>{elements}</tbody></table>);
|
||||
}
|
||||
|
||||
export default ItemIndex;
|
||||
@@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import { ItemBasicLang } from '../../../lib/ItemUtil';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import Functions from '../../../../functions';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
itemLang: ItemBasicLang;
|
||||
}
|
||||
|
||||
const Language = (props: Props) => {
|
||||
const { lang, itemLang } = props;
|
||||
const langStr = {
|
||||
eng: '[en]English[/en][ja]英語[/ja]',
|
||||
jpn: '[en]Japanese[/en][ja]日本語[/ja]',
|
||||
fra: '[en]French[/en][ja]フランス語[/ja]',
|
||||
deu: '[en]German[/en][ja]ドイツ語[/ja]',
|
||||
esl: '[en]Spanish[/en][ja]スペイン語[/ja]',
|
||||
ita: '[en]Italian[/en][ja]イタリア語[/ja]',
|
||||
dut: '[en]Dutch[/en][ja]オランダ語[/ja]',
|
||||
sve: '[en]Swedish[/en][ja]スウェーデン語[/ja]',
|
||||
nor: '[en]Norwegian[/en][ja]ノルウェー語[/ja]',
|
||||
dan: '[en]Danish[/en][ja]デンマーク語[/ja]',
|
||||
fin: '[en]Finnish[/en][ja]フィンランド語[/ja]',
|
||||
por: '[en]Portuguese[/en][ja]ポルトガル語[/ja]',
|
||||
chi: '[en]Chinese[/en][ja]中国語[/ja]',
|
||||
kor: '[en]Korean[/en][ja]韓国語[/ja]',
|
||||
}
|
||||
if (!(itemLang in langStr)) {
|
||||
return null;
|
||||
}
|
||||
return (<span>{Functions.mlang(langStr[itemLang], lang)}</span>);
|
||||
}
|
||||
|
||||
export default Language;
|
||||
@@ -0,0 +1,38 @@
|
||||
.overlay {
|
||||
position: fixed;
|
||||
z-index: 90;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #000000;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
position: fixed;
|
||||
background-color: #d8d8d8;
|
||||
width: 570px;
|
||||
z-index: 100;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.box {
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.download {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.download button {
|
||||
margin: 5px 5px 0;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import React, { ChangeEvent, Component, MouseEvent } from 'react';
|
||||
import { Modal } from 'react-overlays';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import Functions from '../../../../functions';
|
||||
import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil';
|
||||
import DateTime from './DateTime';
|
||||
import FileSize from './FileSize';
|
||||
import styles from './LicenseAgreementDialog.module.css';
|
||||
import Rights from './Rights';
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
lang: MultiLang;
|
||||
file: ItemBasicFile;
|
||||
rights: string;
|
||||
useCc: number;
|
||||
ccCommercialUse: number;
|
||||
ccModification: number;
|
||||
show: boolean;
|
||||
unsetShow: () => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
show: boolean;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
class LicenseAgreementDialog extends Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
show: props.show,
|
||||
disabled: false,
|
||||
};
|
||||
this.handleChangeCheckbox = this.handleChangeCheckbox.bind(this);
|
||||
this.handleClickDownload = this.handleClickDownload.bind(this);
|
||||
this.handleClickCancel = this.handleClickCancel.bind(this);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||
if (nextProps.show && !prevState.show) {
|
||||
return { disabled: true, show: nextProps.show };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
handleChangeCheckbox(e: ChangeEvent<HTMLInputElement>) {
|
||||
const disabled = e.target.value === '0';
|
||||
this.setState({ disabled });
|
||||
}
|
||||
|
||||
handleClickDownload(e: MouseEvent<HTMLButtonElement>) {
|
||||
this.props.unsetShow();
|
||||
this.setState({ show: false });
|
||||
}
|
||||
|
||||
handleClickCancel(e: MouseEvent<HTMLButtonElement>) {
|
||||
this.props.unsetShow();
|
||||
this.setState({ show: false });
|
||||
}
|
||||
|
||||
renderBackdrop(props: any) {
|
||||
return <div className={styles.overlay} {...props} />;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang } = this.props;
|
||||
const date = new Date(this.props.file.timestamp);
|
||||
const timestamp = Math.floor(date.valueOf() / 1000);
|
||||
const url = ItemUtil.getFileUrl(this.props.file);
|
||||
return (
|
||||
<Modal className={styles.dialog} show={this.state.show} onHide={this.handleClickCancel} renderBackdrop={this.renderBackdrop}>
|
||||
<div>
|
||||
<div>
|
||||
{Functions.mlang('[en]Download file information[/en][ja]ダウンロードするファイルの情報[/ja]', lang)}
|
||||
<div className={styles.box}>
|
||||
{this.props.file.original_file_name}<br />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td>Type</td><td>: {this.props.file.mime_type}</td></tr>
|
||||
<tr><td>Size</td><td>: <FileSize lang={lang} size={this.props.file.file_size} /></td></tr>
|
||||
<tr><td>Last updated</td><td>: <DateTime lang={lang} date={timestamp} onlyDate={true} /></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
{Functions.mlang('[en]License agreement[/en][ja]ファイルのライセンス[/ja]', lang)}
|
||||
<div className={styles.box}>
|
||||
{Functions.mlang('[en]Please read the following license agreement carefully.[/en][ja]このファイルには下記のライセンスが設定されています。[/ja]', lang)}
|
||||
<div>
|
||||
<Rights lang={lang} rights={this.props.rights} useCc={this.props.useCc} ccCommercialUse={this.props.ccCommercialUse} ccModification={this.props.ccModification} />
|
||||
<input type="radio" name="radio_license" value="1" onChange={this.handleChangeCheckbox} checked={!this.state.disabled} />{Functions.mlang('[en]I accept the terms in the license agreement.[/en][ja]ライセンスに同意します。[/ja]', lang)}<br />
|
||||
<input type="radio" name="radio_license" value="0" onChange={this.handleChangeCheckbox} checked={this.state.disabled} />{Functions.mlang('[en]I do not accept the terms in the license agreement.[/en][ja]ライセンスに同意しません。[/ja]', lang)}<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div className={styles.download}>
|
||||
Acceptance is needed to download this file.
|
||||
<br />
|
||||
<a href={url} download={this.props.file.original_file_name}>
|
||||
<button className="formButton" onClick={this.handleClickDownload} disabled={this.state.disabled}>Download</button>
|
||||
</a>
|
||||
<button className="formButton" onClick={this.handleClickCancel}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(LicenseAgreementDialog);
|
||||
@@ -0,0 +1,23 @@
|
||||
.previewBox {
|
||||
text-align: center;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.previewBox::after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.preview {
|
||||
width: 200px;
|
||||
margin: 0 auto;
|
||||
float: left;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview caption {
|
||||
width: 200px;
|
||||
margin: 5px;
|
||||
font-size: 80%;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import React, { Component } from 'react';
|
||||
import Lightbox from 'react-image-lightbox';
|
||||
import 'react-image-lightbox/style.css';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import Functions from '../../../../functions';
|
||||
import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil';
|
||||
import styles from './Preview.module.css';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
file: ItemBasicFile[];
|
||||
}
|
||||
|
||||
interface State {
|
||||
isOpen: boolean;
|
||||
imageIndex: number;
|
||||
}
|
||||
|
||||
class Preview extends Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
imageIndex: 0,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lang, file } = this.props;
|
||||
const data = file.filter((value) => {
|
||||
return value.file_type_name === 'preview';
|
||||
});
|
||||
if (data.length === 0) {
|
||||
return null;
|
||||
}
|
||||
let imageUrls: string[] = [];
|
||||
const previews = data.map((value, idx) => {
|
||||
const fileUrl = ItemUtil.getFileUrl(value);
|
||||
const previewUrl = ItemUtil.getPreviewFileUrl(value);
|
||||
const caption = Functions.mlang(value.caption, lang);
|
||||
imageUrls.push(fileUrl);
|
||||
return (
|
||||
<figure key={value.file_id} className={styles.preview}>
|
||||
<a href={fileUrl} download={value.original_file_name} onClick={(e) => {
|
||||
e.preventDefault();
|
||||
this.setState({ isOpen: true, imageIndex: idx });
|
||||
}}>
|
||||
<img src={previewUrl} alt={caption} />
|
||||
</a>
|
||||
<figcaption>{caption}</figcaption>
|
||||
</figure>
|
||||
);
|
||||
});
|
||||
const { isOpen, imageIndex } = this.state;
|
||||
return (
|
||||
<>
|
||||
<div className={styles.previewBox}>
|
||||
{previews}
|
||||
</div>
|
||||
{isOpen &&
|
||||
<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;
|
||||
@@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import DateTime from './DateTime';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
year: number;
|
||||
month: number;
|
||||
mday: number;
|
||||
}
|
||||
|
||||
const PublicationDate = (props: Props) => {
|
||||
const { lang, year, month, mday } = props;
|
||||
const d = new Date(year + '-' + month + '-' + mday);
|
||||
const timestamp = Math.floor(d.valueOf() / 1000);
|
||||
return <DateTime lang={lang} date={timestamp} onlyDate={true} />;
|
||||
}
|
||||
|
||||
export default PublicationDate;
|
||||
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import Description from './Description';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
readme: string;
|
||||
}
|
||||
|
||||
const Readme = (props: Props) => {
|
||||
const { lang, readme } = props;
|
||||
return <Description lang={lang} description={readme} className="readme" />;
|
||||
}
|
||||
|
||||
export default Readme;
|
||||
@@ -0,0 +1,74 @@
|
||||
import React, { Component } from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import ItemType from '../../../item-type';
|
||||
import ItemUtil from '../../../lib/ItemUtil';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang
|
||||
relatedTo: number[];
|
||||
}
|
||||
|
||||
interface State {
|
||||
elements: JSX.Element[];
|
||||
}
|
||||
|
||||
class RelatedTo extends Component<Props, State> {
|
||||
|
||||
private isActive: boolean;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
elements: [],
|
||||
};
|
||||
this.isActive = false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
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 } = this.props;
|
||||
if (relatedTo.length === 0) {
|
||||
this.setState({ elements: [] });
|
||||
} else {
|
||||
ItemUtil.getList(relatedTo, (results) => {
|
||||
const elements = results.data.map((item, idx) => {
|
||||
const evenodd = idx % 0 ? 'even' : 'odd';
|
||||
return <tr key={item.item_id}><td className={evenodd}><ItemType.List lang={lang} item={item} /></td></tr>;
|
||||
});
|
||||
if (this.isActive) {
|
||||
this.setState({ elements });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.elements.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<table className="listTable">
|
||||
<tbody>
|
||||
<tr><th>Item summary</th></tr>
|
||||
{this.state.elements}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RelatedTo;
|
||||
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import CreativeCommons, { getCreativeCommonsType } from './CreativeCommons';
|
||||
import Description from './Description';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
rights: string;
|
||||
useCc: number;
|
||||
ccCommercialUse: number;
|
||||
ccModification: number;
|
||||
}
|
||||
|
||||
const Rights = (props: Props) => {
|
||||
const { lang, rights, useCc, ccCommercialUse, ccModification } = props;
|
||||
if (useCc === 0) {
|
||||
return <Description lang={lang} description={rights} className="rights" />;
|
||||
}
|
||||
const ccType = getCreativeCommonsType(ccCommercialUse, ccModification);
|
||||
return <CreativeCommons lang={lang} type={ccType} />;
|
||||
}
|
||||
|
||||
export default Rights;
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { MultiLang } from '../../../../config';
|
||||
import imageButton from '../../../assets/images/simpf_button.png';
|
||||
|
||||
interface Props {
|
||||
lang: MultiLang;
|
||||
url: string;
|
||||
isDetail: boolean;
|
||||
}
|
||||
|
||||
const SimPFLinkIcon = (props: Props) => {
|
||||
const { url, isDetail } = props;
|
||||
const title = 'Online Simulation';
|
||||
const size = isDetail ? 64 : 35;
|
||||
if (url === '') {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<a href={url} target="_blank" rel="noopener noreferrer" title={title}>
|
||||
<img src={imageButton} alt={title} width={size} height={size} />
|
||||
</a>
|
||||
);;
|
||||
}
|
||||
|
||||
export default SimPFLinkIcon;
|
||||
@@ -0,0 +1,39 @@
|
||||
import Author from './Author';
|
||||
import ChangeLog from './ChangeLog';
|
||||
import Contributer from './Contributer';
|
||||
import CreativeCommons from './CreativeCommons';
|
||||
import DateTime from './DateTime';
|
||||
import Description from './Description';
|
||||
import FileSize from './FileSize';
|
||||
import FileDownloadButton from './FileDownloadButton';
|
||||
import FreeKeyword from './FreeKeyword';
|
||||
import ItemFile from './ItemFile';
|
||||
import ItemIndex from './ItemIndex';
|
||||
import Language from './Language';
|
||||
import Preview from './Preview';
|
||||
import PublicationDate from './PublicationDate';
|
||||
import Readme from './Readme';
|
||||
import RelatedTo from './RelatedTo';
|
||||
import Rights from './Rights';
|
||||
|
||||
const ItemTypeField = {
|
||||
Author,
|
||||
ChangeLog,
|
||||
Contributer,
|
||||
CreativeCommons,
|
||||
DateTime,
|
||||
Description,
|
||||
FileDownloadButton,
|
||||
FileSize,
|
||||
FreeKeyword,
|
||||
ItemFile,
|
||||
ItemIndex,
|
||||
Language,
|
||||
Preview,
|
||||
PublicationDate,
|
||||
Readme,
|
||||
RelatedTo,
|
||||
Rights,
|
||||
};
|
||||
|
||||
export default ItemTypeField;
|
||||
@@ -0,0 +1,28 @@
|
||||
import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
|
||||
|
||||
class MemoAdvancedSearch extends AdvancedSearchBase {
|
||||
|
||||
constructor(props: AdvancedSearchBaseProps) {
|
||||
super(props);
|
||||
this.type = 'memo';
|
||||
this.title = 'Memo';
|
||||
this.state.values['title'] = '';
|
||||
this.state.values['keyword'] = '';
|
||||
this.state.values['description'] = '';
|
||||
this.state.values['doi'] = '';
|
||||
this.state.values['item_link'] = '';
|
||||
}
|
||||
|
||||
getRows() {
|
||||
const rows = [
|
||||
{ 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: 'ID', value: this.renderFieldInputText('doi', 50) },
|
||||
{ label: '[en]Item Link[/en][ja]リンク[/ja]', value: this.renderFieldInputText('item_link', 50) },
|
||||
];
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoAdvancedSearch;
|
||||
@@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import XoopsCode from '../../../common/lib/XoopsCode';
|
||||
import Functions from '../../../functions';
|
||||
import { ItemMemo } from '../../lib/ItemUtil';
|
||||
import DetailBase from '../lib/DetailBase';
|
||||
import ItemTypeField from '../lib/field';
|
||||
|
||||
class MemoDetail extends DetailBase {
|
||||
|
||||
getFields() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemMemo;
|
||||
const fields = [
|
||||
{ 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]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]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} type="memo_file" /> },
|
||||
{ label: 'Index', value: <ItemTypeField.ItemIndex lang={lang} index={item.index} /> },
|
||||
{ label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} /> },
|
||||
];
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoDetail;
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import XoopsCode from '../../../common/lib/XoopsCode';
|
||||
import Functions from '../../../functions';
|
||||
import iconFile from '../../assets/images/icon_memo.gif';
|
||||
import { ItemMemo } from '../../lib/ItemUtil';
|
||||
import ListBase, { ListBaseProps } from '../lib/ListBase';
|
||||
|
||||
class MemoList extends ListBase {
|
||||
|
||||
constructor(props: ListBaseProps) {
|
||||
super(props);
|
||||
this.label = 'Memo';
|
||||
this.icon = iconFile;
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemMemo;
|
||||
const link = item.item_link !== '' ? <XoopsCode lang={lang} text={item.item_link} /> : null;
|
||||
return (
|
||||
<>
|
||||
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link><br />
|
||||
{link}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoList;
|
||||
@@ -0,0 +1,15 @@
|
||||
import TopBase, { TopBaseProps } from '../lib/TopBase';
|
||||
import iconFile from '../../assets/images/icon_memo.gif';
|
||||
|
||||
class MemoTop extends TopBase {
|
||||
|
||||
constructor(props: TopBaseProps) {
|
||||
super(props);
|
||||
this.type = 'memo';
|
||||
this.label = 'Memo';
|
||||
this.icon = iconFile;
|
||||
this.description = '[en]Personal Memo Pad.[/en][ja]汎用メモパッド[/ja]';
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoTop;
|
||||
@@ -0,0 +1,13 @@
|
||||
import MemoTop from './MemoTop';
|
||||
import MemoList from './MemoList';
|
||||
import MemoDetail from './MemoDetail';
|
||||
import MemoAdvancedSearch from './MemoAdvancedSearch';
|
||||
|
||||
const ItemTypeMemo = {
|
||||
Top: MemoTop,
|
||||
List: MemoList,
|
||||
Detail: MemoDetail,
|
||||
AdvancedSearch: MemoAdvancedSearch,
|
||||
};
|
||||
|
||||
export default ItemTypeMemo;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { ItemModelSubTypes } from '../../lib/ItemUtil';
|
||||
import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase';
|
||||
|
||||
class ModelAdvancedSearch extends AdvancedSearchBase {
|
||||
|
||||
constructor(props: AdvancedSearchBaseProps) {
|
||||
super(props);
|
||||
this.type = 'model';
|
||||
this.title = 'Model';
|
||||
this.state.values['title'] = '';
|
||||
this.state.values['keyword'] = '';
|
||||
this.state.values['description'] = '';
|
||||
this.state.values['doi'] = '';
|
||||
this.state.values['model_type'] = '';
|
||||
this.state.values['creator'] = '';
|
||||
this.state.values['file.preview.caption'] = '';
|
||||
this.state.values['file.model_data.original_file_name'] = '';
|
||||
}
|
||||
|
||||
getRows() {
|
||||
const rows = [
|
||||
{ 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: 'ID', value: this.renderFieldInputText('doi', 50) },
|
||||
{ label: '[en]Model Type[/en][ja]モデルタイプ[/ja]', value: this.renderFieldSelect('model_type', ItemModelSubTypes) },
|
||||
{ label: '[en]Creator[/en][ja]作成者[/ja]', value: this.renderFieldInputText('creator', 50) },
|
||||
{ label: '[en]Caption[/en][ja]キャプション[/ja]', value: this.renderFieldInputText('file.preview.caption', 50) },
|
||||
{ label: '[en]Model File[/en][ja]モデルファイル[/ja]', value: this.renderFieldInputText('file.model_data.original_file_name', 50) },
|
||||
];
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
export default ModelAdvancedSearch;
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import Functions from '../../../functions';
|
||||
import ItemUtil, { ItemModel } from '../../lib/ItemUtil';
|
||||
import DetailBase from '../lib/DetailBase';
|
||||
import ItemTypeField from '../lib/field';
|
||||
import SimPFLinkIcon from '../lib/field/SimPFLinkIcon';
|
||||
import ModelUtil from './ModelUtil';
|
||||
|
||||
class ModelDetail extends DetailBase {
|
||||
|
||||
getFields() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemModel;
|
||||
const fields = [
|
||||
{ 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]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]Model Type[/en][ja]モデルタイプ[/ja]', value: <ModelUtil.ModelType lang={lang} type={item.model_type} /> },
|
||||
{ label: '[en]Creator[/en][ja]作成者[/ja]', value: <ItemTypeField.Author lang={lang} author={item.creator} /> },
|
||||
{ label: '[en]Preview[/en][ja]プレビュー[/ja]', value: <ItemTypeField.Preview lang={lang} file={item.file} /> },
|
||||
{ label: '[en]Model File[/en][ja]モデルファイル[/ja]', value: <ItemTypeField.ItemFile lang={lang} file={item.file} type="model_data" rights={item.rights} useCc={item.use_cc} ccCommercialUse={item.cc_commercial_use} ccModification={item.cc_modification} downloadLimit={item.attachment_dl_limit} /> },
|
||||
{ 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} /> },
|
||||
{ label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: <ItemTypeField.RelatedTo lang={lang} relatedTo={item.related_to} /> },
|
||||
];
|
||||
const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id);
|
||||
if (simpfLinkUrl !== '') {
|
||||
const field = { label: 'Online Simulation', value: <SimPFLinkIcon lang={lang} url={simpfLinkUrl} isDetail={true} /> };
|
||||
fields.splice(13, 0, field);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
||||
export default ModelDetail;
|
||||
@@ -0,0 +1,31 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Functions from '../../../functions';
|
||||
import iconFile from '../../assets/images/icon_model.gif';
|
||||
import { ItemModel } from '../../lib/ItemUtil';
|
||||
import ListBase, { ListBaseProps } from '../lib/ListBase';
|
||||
|
||||
class ModelList extends ListBase {
|
||||
|
||||
constructor(props: ListBaseProps) {
|
||||
super(props);
|
||||
this.label = 'Model';
|
||||
this.icon = iconFile;
|
||||
}
|
||||
|
||||
renderBody() {
|
||||
const { lang } = this.props;
|
||||
const item = this.props.item as ItemModel;
|
||||
const authors = item.creator.map((author, i) => {
|
||||
return <Fragment key={i}>{i > 0 && ', '}{Functions.mlang(author, lang)}</Fragment>
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Link to={this.url}>{Functions.mlang(item.title, lang)}</Link><br />
|
||||
{authors}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ModelList;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { ItemModelSubTypes } from '../../lib/ItemUtil';
|
||||
import TopBase, { TopBaseProps } from '../lib/TopBase';
|
||||
import iconFile from '../../assets/images/icon_model.gif';
|
||||
|
||||
class ModelTop extends TopBase {
|
||||
|
||||
constructor(props: TopBaseProps) {
|
||||
super(props);
|
||||
this.type = 'model';
|
||||
this.label = 'Model';
|
||||
this.icon = iconFile;
|
||||
this.description = '[en]Model programs/scripts.[/en][ja]モデル プログラム/スクリプト[/ja]';
|
||||
this.subTypes = ItemModelSubTypes;
|
||||
}
|
||||
}
|
||||
|
||||
export default ModelTop;
|
||||