Refactor Inferno components, add areInputsDisabled

This commit is contained in:
Ilya Ig. Petrov 2017-05-18 11:51:34 +05:00
parent e97a2bcff5
commit b01999a737
12 changed files with 115 additions and 146 deletions

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html style="display: none; will-change: contents, display">
<head>
<meta charset="utf-8">
<title>Настройки</title>
</head>
<body>
<div id="app-mount-point">old info</div>
<script src="./dist/bundle.min.js"></script>
</body>
</html>

View File

@ -10,21 +10,12 @@
"babel-preset-flow": "^6.23.0", "babel-preset-flow": "^6.23.0",
"babel-preset-react": "^6.24.1", "babel-preset-react": "^6.24.1",
"babili-webpack-plugin": "^0.0.11", "babili-webpack-plugin": "^0.0.11",
"bel": "^4.6.1",
"concat-stream": "^1.6.0", "concat-stream": "^1.6.0",
"csjs": "^1.1.0",
"csjs-inject": "^1.0.1", "csjs-inject": "^1.0.1",
"csjs-injectify": "^1.0.1",
"flow-bin": "^0.45.0", "flow-bin": "^0.45.0",
"inferno": "^3.1.2", "inferno": "^3.1.2",
"inferno-component": "^3.1.2", "inferno-component": "^3.1.2",
"inferno-create-element": "^3.1.2", "inferno-create-element": "^3.1.2",
"inferno-redux": "^3.1.2",
"microcomponent": "^3.1.1",
"nanomorph": "^4.0.5",
"nanomount": "^1.0.1",
"sheetify": "^6.0.2",
"transform-loader": "^0.2.4",
"webpack": "^2.5.1" "webpack": "^2.5.1"
}, },
"scripts": { "scripts": {

View File

@ -26,12 +26,6 @@ export default function getApp(theState) {
} }
componentDidMount() {
this.showErrors({ message: 'PANIC!' });
}
setStatusTo(msg) { setStatusTo(msg) {
this.setState( this.setState(
@ -140,6 +134,7 @@ export default function getApp(theState) {
setStatusTo: this.setStatusTo.bind(this), setStatusTo: this.setStatusTo.bind(this),
conduct: this.conduct.bind(this), conduct: this.conduct.bind(this),
}, },
areInputsDisabled: this.state.areInputsDisabled,
}); });
return createElement('div', null, [ return createElement('div', null, [

View File

@ -1,6 +1,5 @@
import Inferno from 'inferno'; import Inferno from 'inferno';
import css from 'csjs-inject'; import css from 'csjs-inject';
import Component from 'inferno-component';
export default function getFooter() { export default function getFooter() {
@ -27,7 +26,7 @@ export default function getFooter() {
</section> </section>
<footer class={scopedCss.controlRow + ' horFlex nowrap'}> <footer class={scopedCss.controlRow + ' horFlex nowrap'}>
<input type="button" value="Готово" onClick={() => window.close()} /> <input type="button" value="Готово" disabled={props.areInputsDisabled} onClick={() => window.close()} />
<a href="../troubleshoot/index.html"> <a href="../troubleshoot/index.html">
Проблемы? Проблемы?
</a> </a>

View File

@ -1,5 +1,4 @@
import Inferno from 'inferno'; import Inferno from 'inferno';
import Component from 'inferno-component';
import css from 'csjs-inject'; import css from 'csjs-inject';
export default function getInfoRow() { export default function getInfoRow() {
@ -83,8 +82,7 @@ export default function getInfoRow() {
const camelToDash = (name) => name.replace(/([A-Z])/g, (_, p1) => '-' + p1.toLowerCase()); const camelToDash = (name) => name.replace(/([A-Z])/g, (_, p1) => '-' + p1.toLowerCase());
// const dashToCamel = (name) => name.replace(/-(.)/g, (_, p1) => p1.toUpperCase()); // const dashToCamel = (name) => name.replace(/-(.)/g, (_, p1) => p1.toUpperCase());
const InfoIcon = function InfoIcon(props) {
const InfoIcon = function InfoIcom(props) {
return ( return (
<svg class="icon" style="position: relative; top: 0.08em">$ <svg class="icon" style="position: relative; top: 0.08em">$
@ -94,38 +92,41 @@ export default function getInfoRow() {
}; };
return class InfoRow extends Component { return function InfoRow(props) {
render(props) { props = Object.assign({}, {
idPrefix: '',
ifDashify: false,
htmlAfterLabel: '',
}, props);
props = Object.assign({}, { const iddy = props.idPrefix + ( props.ifDashify ? camelToDash(props.conf.key) : props.conf.key );
idPrefix: '', return (
ifDashify: false, <li class={scopedCss.infoRow + ' horFlex'}>
htmlAfterLabel: '', <input
}, props); type={props.type}
name={props.name}
const iddy = props.idPrefix + ( props.ifDashify ? camelToDash(props.conf.key) : props.conf.key ); checked={props.checked}
return ( id={iddy}
<li class={scopedCss.infoRow + ' horFlex'}> onClick={props.onClick}
<input type={props.type} name={props.name} checked={props.checked} id={iddy} onClick={props.onClick}/> disabled={props.disabled}
<div class={scopedCss.labelContainer}> />
<label for={iddy}>{props.conf.label}</label> <div class={scopedCss.labelContainer}>
{props.children} <label for={iddy}>{props.conf.label}</label>
</div> {props.children}
{props.conf.desc </div>
? ( {props.conf.desc
<div class={scopedCss.desc}> ? (
<InfoIcon /> <div class={scopedCss.desc}>
<div class={scopedCss.tooltip} dangerouslySetInnerHTML={{__html: props.conf.desc}}/> <InfoIcon />
</div>) <div class={scopedCss.tooltip} dangerouslySetInnerHTML={{__html: props.conf.desc}}/>
: (props.conf.url </div>)
&& (<a href={props.conf.url} class={[scopedCss.rightBottomIcon, scopedCss.infoUrl].join(' ')}><InfoIcon /></a>) : (props.conf.url
) && (<a href={props.conf.url} class={[scopedCss.rightBottomIcon, scopedCss.infoUrl].join(' ')}><InfoIcon /></a>)
} )
</li> }
); </li>
);
}
}; };

View File

@ -0,0 +1,62 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
export default function getLastUpdateDate(theState) {
return class LastUpdateDate extends Component {
componentWillMount() {
this.onStorageChangedHandler = (changes) =>
changes.lastPacUpdateStamp.newValue && this.forceUpdate();
chrome.storage.onChanged.addListener( this.onStorageChangedHandler );
}
componentWillUnmount() {
chrome.storage.onChanged.removeListener( this.onStorageChangedHandler );
}
getDate(antiCensorRu) {
let dateForUser = 'никогда';
if( antiCensorRu.lastPacUpdateStamp ) {
let diff = Date.now() - antiCensorRu.lastPacUpdateStamp;
let units = 'мс';
const gauges = [
[1000, 'с'],
[60, 'мин'],
[60, 'ч'],
[24, 'дн'],
[7, ' недель'],
[4, ' месяцев'],
];
for(const g of gauges) {
const diffy = Math.floor(diff / g[0]);
if (!diffy)
break;
diff = diffy;
units = g[1];
}
dateForUser = diff + units + ' назад';
}
return {
text: `${dateForUser} / ${antiCensorRu.pacUpdatePeriodInMinutes/60}ч`,
title: new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU'),
};
}
render(props) {
const date = this.getDate(props.apis.antiCensorRu);
return (<div>Обновлялись: <span class="updateDate" title={date.title}>{ date.text }</span></div>);
}
};
};

View File

@ -1,11 +1,7 @@
// @flow // @flow
//import mComponent from 'microcomponent';
//import html from 'bel';
import css from 'csjs-inject'; import css from 'csjs-inject';
import Inferno from 'inferno'; import Inferno from 'inferno';
import Component from 'inferno-component';
export default function getNotControlledWarning({ flags }) { export default function getNotControlledWarning({ flags }) {
@ -34,22 +30,12 @@ export default function getNotControlledWarning({ flags }) {
} }
`; `;
return class NotControlledWarning extends Component { return function NotControlledWarning(props) {
constructor(props) { return (
<section class={cssClasses.warningContainer + " horPadded"} dangerouslySetInnerHTML={{ __html: props.utils.messages.whichExtensionHtml() }} />
);
super(props); }
}
render(props) {
return (
<section class={cssClasses.warningContainer + " horPadded"} dangerouslySetInnerHTML={{ __html: props.utils.messages.whichExtensionHtml() }} />
);
}
};
} }

View File

@ -3,9 +3,10 @@ import Component from 'inferno-component';
import createElement from 'inferno-create-element'; import createElement from 'inferno-create-element';
import css from 'csjs-inject'; import css from 'csjs-inject';
import getLastUpdateDate from './LastUpdateDate';
import getInfoLi from './InfoLi'; import getInfoLi from './InfoLi';
export default function getPacChooser(...args) { export default function getPacChooser(theState) {
const scopedCss = css` const scopedCss = css`
/* OTHER VERSION */ /* OTHER VERSION */
@ -45,57 +46,8 @@ export default function getPacChooser(...args) {
`; `;
class LastUpdateDate extends Component { const LastUpdateDate = getLastUpdateDate(theState);
const InfoLi = getInfoLi(theState);
constructor(props) {
super(props);
chrome.storage.onChanged.addListener(
(changes) => changes.lastPacUpdateStamp.newValue && this.forceUpdate()
);
}
getDate(antiCensorRu) {
let dateForUser = 'никогда';
if( antiCensorRu.lastPacUpdateStamp ) {
let diff = Date.now() - antiCensorRu.lastPacUpdateStamp;
let units = 'мс';
const gauges = [
[1000, 'с'],
[60, 'мин'],
[60, 'ч'],
[24, 'дн'],
[7, ' недель'],
[4, ' месяцев'],
];
for(const g of gauges) {
const diffy = Math.floor(diff / g[0]);
if (!diffy)
break;
diff = diffy;
units = g[1];
}
dateForUser = diff + units + ' назад';
}
return {
text: `${dateForUser} / ${antiCensorRu.pacUpdatePeriodInMinutes/60}ч`,
title: new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU'),
};
}
render(props) {
const date = this.getDate(props.apis.antiCensorRu);
return (<div>Обновлялись: <span class="updateDate" title={date.title}>{ date.text }</span></div>);
}
}
const InfoLi = getInfoLi(...args);
return class PacChooser extends Component { return class PacChooser extends Component {
@ -170,6 +122,7 @@ export default function getPacChooser(...args) {
type="radio" type="radio"
name="pacProvider" name="pacProvider"
checked={iddyToCheck === provConf.key} checked={iddyToCheck === provConf.key}
disabled={props.areInputsDisabled}
> >
&nbsp;<a href="" class={scopedCss.updateButton} onClick={(evt) => { evt.preventDefault(); updatePac(); }}>[обновить]</a> &nbsp;<a href="" class={scopedCss.updateButton} onClick={(evt) => { evt.preventDefault(); updatePac(); }}>[обновить]</a>
</InfoLi>) </InfoLi>)
@ -181,6 +134,7 @@ export default function getPacChooser(...args) {
name="pacProvider" name="pacProvider"
conf={{key: 'none', label: 'Отключить'}} conf={{key: 'none', label: 'Отключить'}}
checked={iddyToCheck === 'none'} checked={iddyToCheck === 'none'}
disabled={props.areInputsDisabled}
/> />
</ul> </ul>
<div id="updateMessage" class="horFlex" style="align-items: center"> <div id="updateMessage" class="horFlex" style="align-items: center">

View File

@ -1,6 +1,3 @@
//import mComponent from 'microcomponent';
//import html from 'bel';
import Inferno, { linkEvent } from 'inferno'; import Inferno, { linkEvent } from 'inferno';
import Component from 'inferno-component'; import Component from 'inferno-component';
import css from 'csjs-inject'; import css from 'csjs-inject';
@ -99,8 +96,8 @@ export default function getTabsPannel({ flags }) {
{ {
visibility: initial; visibility: initial;
} }
.navLabels li:after { .navLabels li {
content: '\\a0'; margin: 0 0.125em; /* 1.5px */
} }
/* LABELS ends. */ /* LABELS ends. */

View File

@ -1,4 +1,4 @@
export default function append(document, props) { export default function append(document, { flags }) {
// innerText converts \n to <br>, so: // innerText converts \n to <br>, so:
document.head.querySelector('style').innerHTML = ` document.head.querySelector('style').innerHTML = `
@ -12,7 +12,7 @@ export default function append(document, props) {
--cr-icon-selected: #d7d7d7; --cr-icon-selected: #d7d7d7;
--cr-popup-border: #bababa; --cr-popup-border: #bababa;
--cr-grey-panel: #f2f2f2; --cr-grey-panel: #f2f2f2;
max-width: 24em; ${ flags.ifInsideOptionsPage ? '' : 'max-width: 24em;' }
} }
/* BASE ELEMENTS */ /* BASE ELEMENTS */
@ -68,7 +68,7 @@ export default function append(document, props) {
/* IF INSIDE OPTIONS */ /* IF INSIDE OPTIONS */
${ ${
props.flags.ifInsideOptionsPage flags.ifInsideOptionsPage
? ` ? `
ul, ol { ul, ol {

View File

@ -1,15 +1,10 @@
// @flow // @flow
import Inferno from 'inferno'; import Inferno from 'inferno';
import Component from 'inferno-component';
import createElement from 'inferno-create-element'; import createElement from 'inferno-create-element';
import { createStore } from 'redux';
import css from 'csjs-inject';
import appendGlobalCss from './globalCss'; import appendGlobalCss from './globalCss';
import getApp from './components/App'; import getApp from './components/App';
/* /*
#list-of-notifiers { #list-of-notifiers {
margin-left: 0.4em; margin-left: 0.4em;