diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js index 1148c56..c9ee179 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js @@ -30,7 +30,7 @@ export default function getProxyEditor(theState) { padding: 0; } /* PROXY ROW */ - table.editor tr.proxyRow td:first-child { + table.editor tr.proxyRow td:nth-child(2) { text-align: center; } @@ -78,7 +78,8 @@ export default function getProxyEditor(theState) { } /* LAST COLUMN: BUTTONS */ - table.editor tr > *:nth-last-child(1) { + table.editor tr > *:nth-last-child(1), + table.editor tr.proxyRow > td:first-child { text-align: center; padding: 0; position: relative; @@ -123,6 +124,10 @@ export default function getProxyEditor(theState) { return true; }; + const splitBySemi = (proxyString) => proxyString.replace(/#.*$/mg, '').trim().split(/\s*;\s*/g).filter((s) => s); + const joinBySemi = (strs) => strs.join(';\n') + ';'; + const normilizeProxyString = (str) => joinBySemi(splitBySemi(str)); + const PROXY_TYPE_LABEL_PAIRS = [['PROXY', 'PROXY/HTTP'],['HTTPS'],['SOCKS4'],['SOCKS5'],['SOCKS']]; @@ -181,12 +186,35 @@ export default function getProxyEditor(theState) { const hostname = elements.hostname; const port = elements.port; - that.props.updateProxyStringRaw( + that.props.setProxyStringRaw( `${that.props.proxyStringRaw} ${type} ${hostname}:${port};`.trim() ); } + handleDelete(that, {proxyAsString, index}) { + + event.preventDefault(); + const proxyStrings = splitBySemi(that.props.proxyStringRaw); + proxyStrings.splice(index, 1); + + that.props.setProxyStringRaw( joinBySemi(proxyStrings) ); + + } + + raisePriority(that, {proxyAsString, index}) { + + event.preventDefault(); + if (index < 1) { + return; + } + const proxyStrings = splitBySemi(that.props.proxyStringRaw); + proxyStrings.splice(index - 1, 2, proxyStrings[index], proxyStrings[index-1]); + + that.props.setProxyStringRaw( joinBySemi(proxyStrings) ); + + } + handleSubmit(that, event) { event.preventDefault(); @@ -201,7 +229,7 @@ export default function getProxyEditor(theState) { - @@ -209,7 +237,7 @@ export default function getProxyEditor(theState) { {/* ADD NEW PROXY STARTS. */} - {/* ADD NEW PROXY ENDS. */} { - this.props.proxyStringRaw.split(/\s*;\s*/g).filter((s) => s).map((proxyAsString) => { + splitBySemi(this.props.proxyStringRaw).map((proxyAsString, index) => { - const [type, addr] = proxyAsString.trim().split(/\s/); + const [type, addr] = proxyAsString.trim().split(/\s+/); const [hostname, port] = addr.split(':'); return ( - + ); @@ -279,14 +315,25 @@ export default function getProxyEditor(theState) { } } + const getInitState = () => ({ + ifHasErrors: false, + stashedExports: false, + }); + class ExportsEditor extends Component { constructor(props) { + super(props); - this.state = { - ifHasErrors: false, - stashedExports: false, - }; + this.state = getInitState(); + + } + + resetState(that, event) { + + that.setState(getInitState()); + event.preventDefault(); + } getErrorsInStashedExports() { @@ -294,10 +341,7 @@ export default function getProxyEditor(theState) { if(this.state.stashedExports === false) { return; } - const errors = this.state.stashedExports.trim() - .replace(/#.*$/mg, '') - .split(/\s*;\s*/) - .filter((s) => s) + const errors = splitBySemi(this.state.stashedExports) .map((proxyAsString) => { const [rawType, addr, ...rest] = proxyAsString.split(/\s+/); @@ -340,7 +384,7 @@ export default function getProxyEditor(theState) { that.props.funs.showErrors(...errors); return; } - that.props.updateProxyStringRaw(that.state.stashedExports); + that.props.setProxyStringRaw(that.state.stashedExports); } that.setState({ stashedExports: false, @@ -352,11 +396,9 @@ export default function getProxyEditor(theState) { handleTextareaChange(that, event) { - let newVal = event.target.value.trim(); - if (newVal && !newVal.endsWith(';')) { - newVal += ';'; - } - that.setState({stashedExports: newVal}); + that.setState({ + stashedExports: normilizeProxyString(event.target.value), + }); } @@ -369,6 +411,8 @@ export default function getProxyEditor(theState) { render(props) { + const reset = linkEvent(this, this.resetState); + return (
протокол домен / IP порт + протокол домен / IP порт
+ @@ -243,6 +272,7 @@ export default function getProxyEditor(theState) { name="port" onInvalid={linkEvent(this, this.showInvalidMessage)} onkeydown={onlyPort} + tabindex="2" /> @@ -255,17 +285,23 @@ export default function getProxyEditor(theState) {
{type}{hostname}{port} - -
- {/**/} + +
{type}{hostname}{port} +
@@ -379,8 +423,8 @@ export default function getProxyEditor(theState) { this.state.stashedExports === false ? 'Жду изменений...' : (this.state.ifHasErrors - ? (Сбросьте изменения или поправьте) - : (Сбросить изменения) + ? (Сбросьте изменения или поправьте) + : (Сбросить изменения) ) } @@ -440,7 +484,7 @@ PROXY foobar.com:8080; # Not HTTP!`.trim()} const props = Object.assign({ proxyStringRaw: this.state.proxyStringRaw, onSwitch: this.handleSwitch, - updateProxyStringRaw: (newVal) => this.setState({proxyStringRaw: newVal}), + setProxyStringRaw: (newVal) => this.setState({proxyStringRaw: newVal}), }, originalProps); return this.state.ifExportsMode diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js__before-refactoring b/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js__before-refactoring deleted file mode 100644 index 116d3bd..0000000 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js__before-refactoring +++ /dev/null @@ -1,389 +0,0 @@ -import Inferno, {linkEvent} from 'inferno'; -import Component from 'inferno-component'; -import css from 'csjs-inject'; - -export default function getProxyEditor(theState) { - - const scopedCss = css` - - table.editor { - border-collapse: collapse; - /*border-style: hidden;*/ - width: 100%; - margin: 0.5em 0; - background-color: #f3f5f6; - } - - table.editor ::-webkit-input-placeholder { - color: #c9c9c9; - } - - table.editor td, table.editor th { - border: 1px solid #ccc; - text-align: left; - height: 100%; - } - - /* ADD PANEL */ - table.editor tr.addPanel td { - padding: 0; - } - /* PROXY ROW */ - table.editor tr.proxyRow td:first-child { - text-align: center; - } - - table.editor th:not(:last-child) { - padding: 0 0.6em; - } - - table.editor input:not([type="submit"]), - table.editor select, - table.editor select:hover { - border: none; - background: inherit !important; - } - table.editor select, - table.editor select:hover { - -webkit-appearance: menulist !important; - box-shadow: none !important; - } - table.editor input { - width: 100%; - } - - /* BUTTONS */ - table.editor input[type="submit"], - table.editor button { - min-width: 0; - min-height: 0; - width: 100%; - padding: 0; - border: none; - } - .only { - /*height: 100%;*/ - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - } - table.editor .add { - font-weight: 900; - } - table.editor .export { - padding-right: 2px; - } - - /* LAST COLUMN: BUTTONS */ - table.editor tr > *:nth-last-child(1) { - text-align: center; - padding: 0; - position: relative; - min-width: 1em; - } - /* LAST-2 COLUMN: HOSTNAME - table.editor td:nth-last-child(3) { - padding-left: 2px; - }*/ - .noPad { - padding: 0; - } - .padLeft { - padding-left: 2px; - } - - textarea.textarea { - width: 100% !important; - min-height: 100%; - height: 6em; - border-width: 1px 0 0 0; - /*border: none;*/ - } - - table.editor input:invalid { - color: red !important; - border-radius: 0; - border-bottom: 1px dotted red !important; - } - - `; - - const UI_RAW = 'ui-proxy-string-raw'; - const MAX_PORT = 65535; - const onlyPort = function onlyPort(event) { - - if (!event.ctrlKey && (/^\D$/.test(event.key) || /^\d$/.test(event.key) && parseInt(`${this.value}${event.key}`) > MAX_PORT)) { - event.preventDefault(); - return false; - } - // Digits, Alt, Tab, Enter, etc. - return true; - - }; - const PROXY_TYPE_LABEL_PAIRS = [['PROXY', 'PROXY/HTTP'],['HTTPS'],['SOCKS4'],['SOCKS5'],['SOCKS']]; - - return class ProxyEditor extends Component { - - constructor(props) { - - super(props); - this.state = { - proxyStringRaw: localStorage.getItem(UI_RAW) || '', - ifExportsMode: false, - - ifChangesStashedForApply: false, - stashedExports: false, - ifExportsHaveErrors: false, - - newType: 'HTTPS', - }; - - this.switchBtn = ( - - ); - - } - - handleTextareaChange(that, event) { - - that.setState({stashedExports: event.target.value}); - - } - preventLostOfChanges() { - - window.onbeforeunload = () => true; // TODO - - } - - findErrorsForStashedExports() { - - const valid = true; - if(this.state.stashedExports === false) { - return valid; - } - const errors = this.state.stashedExports.trim() - .split(/\s*;\s*/) - .filter((s) => s) - .map((proxyAsString) => { - - const [rawType, addr] = proxyAsString.split(/\s+/); - const knownTypes = PROXY_TYPE_LABEL_PAIRS.map(([type, label]) => type); - if( !knownTypes.includes(rawType.toUpperCase()) ) { - return new Error( - `Неверный тип ${rawType}. Известные типы: ${knownTypes.join(', ')}.` - ); - } - if (!(addr && /^[^:]+:\d+$/.test(addr))) { - return new Error( - `Адрес прокси "${addr || ''}" не соответствует формату "<домен_или_IP>:<порт_из_цифр>".` - ); - } - const [hostname, rawPort] = addr.split(':'); - const port = parseInt(rawPort); - if (port < 0 || port > 65535) { - return new Error( - `Порт "${rawPort}" должен быть целым числом от 0 до 65535.` - ); - } - return false; - - }).filter((e) => e); - return errors && errors.length ? errors : false; - - } - - handleModeSwitch(that, event) { - - event.preventDefault(); // No form submit. - let newProxyStringRaw = that.state.proxyStringRaw; - - const doSwitch = () => that.setState({ - ifExportsMode: !that.state.ifExportsMode, - proxyStirngRaw: newProxyStringRaw, - stashedExports: false, - ifExportsHaveErrors: false, - }); - - if (that.state.stashedExports !== false) { - - const errors = that.findErrorsForStashedExports(); - if (!errors) { - newProxyStringRaw = that.state.stashedExports; - } else { - that.setState({ifExportsHaveErrors: true}); - return that.props.funs.showErrors(...errors); - } - } - doSwitch(); - - } - - showInvalidMessage(that, event) { - - that.props.funs.showErrors({message: event.target.validationMessage}); - - } - - handleTypeSelect(that, event) { - - that.state.newType = event.target.value; - - } - - handleSubmit(that, event) { - - !that.state.ifExportsMode ? that.handleAdd(that, event) : that.handleModeSwitch(that, event); - - } - - handleAdd(that, event) { - - const form = event.target; - const elements = Array.from(form.elements).reduce((acc, el, index) => { - - acc[el.name || index] = el.value; - el.value = ''; - return acc; - - }, {}); - const type = that.state.newType; - const hostname = elements.hostname; - const port = elements.port; - - that.setState({proxyStringRaw: `${that.state.proxyStringRaw} ${type} ${hostname}:${port};`.trim()}); - - event.preventDefault(); - - } - render(props) { - - return ( - - { - !this.state.ifExportsMode - ? (( -
- - - - - - - {/* ADD NEW PROXY STARTS. */} - - - - - - - {/* ADD NEW PROXY ENDS. */} - { - this.state.proxyStringRaw.split(/\s*;\s*/g).filter((s) => s).map((proxyAsString) => { - - const [type, addr] = proxyAsString.trim().split(/\s/); - const [hostname, port] = addr.split(':'); - return ( - - - - - ); - - }) - } - -
протокол домен / IP порт {this.switchBtn}
- - - {/* LAST-2: HOSTNAME */} - - - {/* LAST-1: PORT */} - - - {/* LAST */} - -
{type}{hostname}{port} - -
- -
- - )) : (( - - - - - - - - - - -
- { - this.state.stashedExports === false - ? 'Жду изменений...' - : (this.state.ifExportsHaveErrors - ? (Сбросьте изменения или поправьте) - : (Сбросить изменения) - ) - } - {this.switchBtn}