Commit 6c06619e authored by Laurent Wouters's avatar Laurent Wouters
Browse files

Refactoring the extension

parent 57b44e7dfa47
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="stylesheet" href="main.css">
<title>
Linked Data Browser
</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="bootstrap.min.js"></script>
<script type="text/javascript" src="main.js"></script></body>
</html>
\ No newline at end of file
#root {
width: 400pt;
margin: 10pt;
font-size: 12pt;
}
select,
option,
input {
font-size: 10pt;
}
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 30px;
height: 17px;
}
/* Hide default HTML checkbox */
.switch input {
display: none;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: 0.4s;
transition: 0.4s;
}
.slider:before {
position: absolute;
content: "";
height: 13px;
width: 13px;
left: 2px;
bottom: 2px;
background-color: white;
-webkit-transition: 0.4s;
transition: 0.4s;
}
input:checked + .slider {
background-color: #2196f3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196f3;
}
input:checked + .slider:before {
-webkit-transform: translateX(13px);
-ms-transform: translateX(13px);
transform: translateX(13px);
}
/* Rounded sliders */
.slider.round {
border-radius: 17px;
}
.slider.round:before {
border-radius: 50%;
}
/*******************************************************************************
* Copyright 2003-2018 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
*
* This file is part of CubicWeb.
*
* CubicWeb is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 2.1 of the License, or (at your option)
* any later version.
*
* CubicWeb is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
import * as LANGUAGES from "../common/data.iso639.json";
import React = require("react");
import ReactDOM = require("react-dom");
import { TabData, NO_DATA, DataSource } from "../common/data";
import { application, definition } from "@logilab/libview";
import {
getCurrentTabId,
getTabData,
getViewRegistry,
refreshTab,
reloadViewRegistry,
setTabData,
addViewSource,
removeViewSource
} from "../common/messages";
interface State {
pane: string;
tabId: number;
tabData: TabData;
registry: definition.ViewRegistry;
registryNewSourceName: string;
registryNewSourceURI: string;
showViews: boolean;
}
class Popup extends React.Component<{}, State> {
state: State;
constructor(props: any) {
super(props);
this.state = {
pane: "loading",
tabId: -1,
tabData: new TabData(),
registry: null,
registryNewSourceName: "",
registryNewSourceURI: "",
showViews: true
};
this.onButtonRefreshPage = this.onButtonRefreshPage.bind(this);
this.onButtonReloadRegistry = this.onButtonReloadRegistry.bind(this);
this.onPaneTab = this.onPaneTab.bind(this);
this.onPaneSources = this.onPaneSources.bind(this);
this.onPaneViews = this.onPaneViews.bind(this);
this.onUpdateTabCommand = this.onUpdateTabCommand.bind(this);
this.onTabCommandActivate = this.onTabCommandActivate.bind(this);
this.onTabCommandAutomatic = this.onTabCommandAutomatic.bind(this);
this.onTabCommandSelectSource = this.onTabCommandSelectSource.bind(this);
this.onTabCommandSelectView = this.onTabCommandSelectView.bind(this);
this.onTabCommandSelectLanguage = this.onTabCommandSelectLanguage.bind(
this
);
this.onRegistryUpdateNewSourceName = this.onRegistryUpdateNewSourceName.bind(
this
);
this.onRegistryUpdateNewSourceUri = this.onRegistryUpdateNewSourceUri.bind(
this
);
this.onRegistryAddSource = this.onRegistryAddSource.bind(this);
this.onRegistryRemoveSource = this.onRegistryRemoveSource.bind(this);
this.renderLoading = this.renderLoading.bind(this);
this.renderTabData = this.renderTabData.bind(this);
this.renderSources = this.renderSources.bind(this);
this.renderViews = this.renderViews.bind(this);
let self = this;
getCurrentTabId().then((tabId: number) => {
var remaining = 2;
getTabData(tabId).then((response: TabData) => {
self.state.pane = "tab";
self.state.tabId = tabId;
self.state.tabData.updateWith(response);
self.state.tabData.sources = self.state.tabData.sources.concat(
response.sources
);
self.state.tabData.mainSource = response.mainSource;
self.state.tabData.primaryTopic = response.primaryTopic;
remaining -= 1;
if (remaining == 0) self.setState(self.state);
});
getViewRegistry().then((registry: definition.ViewRegistry) => {
self.state.registry = registry;
remaining -= 1;
if (remaining == 0) self.setState(self.state);
});
});
}
onButtonRefreshPage() {
refreshTab(this.state.tabId);
}
onButtonReloadRegistry() {
let self = this;
reloadViewRegistry().then((registry: definition.ViewRegistry) => {
self.state.registry = registry;
self.setState(self.state);
});
}
onPaneTab() {
this.state.pane = "tab";
this.setState(this.state);
}
onPaneSources() {
this.state.pane = "sources";
this.setState(this.state);
}
onPaneViews() {
this.state.pane = "views";
this.setState(this.state);
}
onUpdateTabCommand() {
let self = this;
setTabData(self.state.tabId, self.state.tabData).then(
(tabData: TabData) => {
self.state.tabData.mainSource = tabData.mainSource;
self.setState(self.state);
}
);
}
onTabCommandActivate(event: React.FormEvent<HTMLInputElement>) {
this.state.tabData.command.isActive = event.currentTarget.checked;
this.onUpdateTabCommand();
}
onTabCommandAutomatic(event: React.FormEvent<HTMLInputElement>) {
this.state.tabData.command.isAutomatic = event.currentTarget.checked;
if (this.state.tabData.command.isAutomatic) {
this.state.tabData.command.selectedSource = "";
this.state.tabData.command.selectedView = "";
}
this.onUpdateTabCommand();
}
onTabCommandSelectSource(event: React.FormEvent<HTMLSelectElement>) {
this.state.tabData.command.selectedSource = event.currentTarget.value;
if (this.state.tabData.command.isAutomatic) {
this.state.tabData.command.selectedSource = "";
this.state.tabData.command.selectedView = "";
this.state.tabData.command.selectedLanguage = application.NO_LANGUAGE;
}
this.onUpdateTabCommand();
}
onTabCommandSelectView(event: React.FormEvent<HTMLSelectElement>) {
this.state.tabData.command.selectedView = event.currentTarget.value;
if (this.state.tabData.command.isAutomatic) {
this.state.tabData.command.selectedSource = "";
this.state.tabData.command.selectedView = "";
this.state.tabData.command.selectedLanguage = application.NO_LANGUAGE;
}
this.onUpdateTabCommand();
}
onTabCommandSelectLanguage(event: React.FormEvent<HTMLSelectElement>) {
let language: application.Language = LANGUAGES.find(
(value: application.Language) =>
value.iso639_1 == event.currentTarget.value
);
this.state.tabData.command.selectedLanguage =
language == undefined ? application.NO_LANGUAGE : language;
if (this.state.tabData.command.isAutomatic) {
this.state.tabData.command.selectedSource = "";
this.state.tabData.command.selectedView = "";
this.state.tabData.command.selectedLanguage = application.NO_LANGUAGE;
}
this.onUpdateTabCommand();
}
onRegistryUpdateNewSourceName(event: React.FormEvent<HTMLInputElement>) {
this.state.registryNewSourceName = event.currentTarget.value;
this.setState(this.state);
}
onRegistryUpdateNewSourceUri(event: React.FormEvent<HTMLInputElement>) {
this.state.registryNewSourceURI = event.currentTarget.value;
this.setState(this.state);
}
onRegistryAddSource() {
let newSource: definition.ViewRegistrySourceRemote = {
kind: definition.ViewRegistrySourceKind.remote,
name: this.state.registryNewSourceName,
uri: this.state.registryNewSourceURI
};
let self = this;
addViewSource(newSource).then((registry: definition.ViewRegistry) => {
self.state.registry = registry;
self.state.registryNewSourceName = "";
self.state.registryNewSourceURI = "";
self.setState(self.state);
});
}
onRegistryRemoveSource(index: number) {
let self = this;
removeViewSource(index).then((registry: definition.ViewRegistry) => {
self.state.registry = registry;
self.state.registryNewSourceName = "";
self.state.registryNewSourceURI = "";
self.setState(self.state);
});
}
render() {
if (this.state.pane == "loading") {
return this.renderLoading();
} else if (this.state.pane == "tab") {
return this.renderTabData();
} else if (this.state.pane == "sources") {
return this.renderSources();
} else if (this.state.pane == "views") {
return this.renderViews();
}
}
renderLoading() {
return (
<div
style={{
width: "90%",
marginLeft: "5%",
marginTop: "5vh",
marginBottom: "5vh"
}}
>
<div className="alert alert-info" role="alert">
Loading
</div>
</div>
);
}
renderTabData() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-2">
<a onClick={this.onPaneSources} title="Configuration">
<span style={{ fontSize: "20pt", cursor: "pointer" }}>
{"\u2699"}
</span>
</a>
</div>
<div className="col-2">
<a onClick={this.onButtonRefreshPage} title="Refresh this page">
<span style={{ fontSize: "20pt", cursor: "pointer" }}>
{"\u21bb"}
</span>
</a>
</div>
<div className="col-8">
<span style={{ fontSize: "17pt" }}>Current tab</span>
</div>
</div>
<hr />
<div className="row">
<div className="col-4">
<label>Active</label>
</div>
<div className="col-8">
<label className="switch">
<input
type="checkbox"
id="fieldActive"
checked={this.state.tabData.command.isActive}
onChange={this.onTabCommandActivate}
/>
<span className="slider round" />
</label>
</div>
</div>
<div className="row">
<div className="col-4">
<label>Auto config</label>
</div>
<div className="col-8">
<label className="switch">
<input
type="checkbox"
id="fiedAuto"
checked={this.state.tabData.command.isAutomatic}
onChange={this.onTabCommandAutomatic}
style={{ width: "250px" }}
/>
<span className="slider round" />
</label>
</div>
</div>
<div className="row">
<div className="col-4">
<label>Primary topic</label>
</div>
<div className="col-8">
<input
className="form-control"
readOnly={true}
value={this.state.tabData.primaryTopic}
style={{ width: "250px" }}
/>
</div>
</div>
<div className="row">
<div className="col-4">
<label>Data source</label>
</div>
<div className="col-8">
<select
className="form-control"
id="fieldDataSource"
disabled={this.state.tabData.command.isAutomatic}
onChange={this.onTabCommandSelectSource}
value={this.state.tabData.command.selectedSource}
style={{ width: "250px" }}
>
<option key={"view-default"} value="">
{"-- auto --"}
</option>
{this.state.tabData.sources
.filter((source: DataSource) => source != NO_DATA)
.map((source: DataSource, index: number) => (
<option key={"source" + index} value={source.url}>
{source.name}
</option>
))}
</select>
</div>
</div>
<div className="row">
<div className="col-4">
<label>View</label>
</div>
<div className="col-8">
<select
className="form-control"
id="fiedView"
disabled={this.state.tabData.command.isAutomatic}
onChange={this.onTabCommandSelectView}
value={this.state.tabData.command.selectedView}
style={{ width: "250px" }}
>
<option key={"view-default"} value="">
{"-- auto --"}
</option>
{Object.keys(this.state.registry.descriptors)
.map((key: string) => this.state.registry.descriptors[key])
.sort(
(
a: definition.ViewDescriptor,
b: definition.ViewDescriptor
): number => a.name.localeCompare(b.name)
)
.map((descriptor: definition.ViewDescriptor, index: number) => {
return (
<option key={"view-" + index} value={descriptor.identifier}>
{descriptor.name + " (" + descriptor.identifier + ")"}
</option>
);
})}
</select>
</div>
</div>
<div className="row">
<div className="col-4">
<label>Language</label>
</div>
<div className="col-8">
<select
className="form-control"
id="fieldLanguage"
disabled={this.state.tabData.command.isAutomatic}
onChange={this.onTabCommandSelectLanguage}
value={this.state.tabData.command.selectedLanguage.iso639_1}
style={{ width: "250px" }}
>
<option key={"view-default"} value="">
{"-- auto --"}
</option>
{LANGUAGES.sort(
(a: application.Language, b: application.Language) =>
a.name.localeCompare(b.name)
).map((language: application.Language, index: number) => {
return (
<option key={"language-" + index} value={language.iso639_1}>
{language.name + " (" + language.iso639_2 + ")"}
</option>
);
})}
</select>
</div>
</div>
</div>
);
}
renderSources() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-2">
<a onClick={this.onPaneTab} title="Back">
<span style={{ fontSize: "20pt", cursor: "pointer" }}>
{"\u2190"}
</span>
</a>
<a onClick={this.onPaneViews} title="Available views">
<span style={{ fontSize: "20pt", cursor: "pointer" }}>
{"\u23FF"}
</span>
</a>
</div>
<div className="col-2">
<a onClick={this.onButtonReloadRegistry} title="Reload registry">
<span style={{ fontSize: "20pt", cursor: "pointer" }}>
{"\u21bb"}
</span>
</a>
</div>
<div className="col-8">
<span style={{ fontSize: "17pt" }}>Registered sources</span>
</div>
</div>
<hr />
<div className="row">
<div className="col-4">New source name:</div>
<div className="col-8">
<input
className="form-control"
onChange={this.onRegistryUpdateNewSourceName}
value={this.state.registryNewSourceName}
/>
</div>
</div>
<div className="row">
<div className="col-4">New source URI:</div>
<div className="col-8">
<input
className="form-control"
onChange={this.onRegistryUpdateNewSourceUri}
value={this.state.registryNewSourceURI}
/>
</div>
</div>
<div className="row">
<div className="col-4" />
<div className="col-8">
<a className="btn btn-primary" onClick={this.onRegistryAddSource}>
OK
</a>
</div>
</div>
<hr />
{this.state.registry.sources.map(
(source: definition.ViewRegistrySource, index: number) => {
return (
<div className="row" key={"source-" + index}>
<div className="col-2">
{source.kind != definition.ViewRegistrySourceKind.inline ? (
<a title="Remove this source">
<span
onClick={() => this.onRegistryRemoveSource(index)}
style={{ cursor: "pointer" }}
className="text-danger"
>
{"\u2716"}
</span>
</a>
) : (
<span />
)}
</div>
<div className="col-10">
<span>{source.name}</span>
{source.kind == definition.ViewRegistrySourceKind.remote ? (
<span>
{" : "}
<a
href={
(source as definition.ViewRegistrySourceRemote).uri
}
>
{(source as definition.ViewRegistrySourceRemote).uri}
</a>
</span>