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 335948e..73b82e6 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 @@ -460,6 +460,18 @@ PROXY foobar.com:8080; # Not HTTP!`.trim()} } + const migrate = (proxyStringRaw) => { + /* In the old format \n\r? could be used as a separator. */ + + return proxyStringRaw + .replace(/#.*$/mg, '') // Strip comments. + .split( /(?:[^\S\r\n]*(?:;|\r?\n)+[^\S\r\n]*)+/g ) + .map( (p) => p.trim() ) + .filter((p) => p) + .join(';\n'); + + }; + let waitingTillMount = []; return class ProxyEditor extends Component { @@ -468,7 +480,7 @@ PROXY foobar.com:8080; # Not HTTP!`.trim()} super(props); const oldValue = typeof props.conf.value === 'string' && props.conf.value; - const newValue = oldValue || localStorage.getItem(UI_RAW) || ''; + const newValue = migrate(oldValue || localStorage.getItem(UI_RAW) || ''); this.state = { proxyStringRaw: newValue, ifExportsMode: false, diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js_replace b/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js_replace deleted file mode 100644 index 85ca06d..0000000 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/pages/options/src/components/ProxyEditor.js_replace +++ /dev/null @@ -1,508 +0,0 @@ -import Inferno, {linkEvent} from 'inferno'; -import Component from 'inferno-component'; -import createElement from 'inferno-create-element'; -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:nth-child(2) { - 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), - table.editor tr.proxyRow > td:first-child { - 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 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']]; - - - const SwitchButton = (props) => - ( - - ); - - class TabledEditor extends Component { - - constructor(props) { - - super(props); - this.state = { - selectedNewType: 'HTTPS', - }; - - } - - handleTypeSelect(that, event) { - - that.setState({ - selectedNewType: event.target.value, - }); - - } - - showInvalidMessage(that, event) { - - that.props.funs.showErrors({message: event.target.validationMessage}); - - } - - handleModeSwitch(that) { - - that.props.onSwitch(); - - } - - 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.selectedNewType; - const hostname = elements.hostname; - const port = elements.port; - - that.props.setProxyStringRaw( - `${that.props.proxyStringRaw.trim()}\n;${type} ${hostname}:${port};`.trim() - ); - - } - - handleDelete(that, {proxyAsString, index}) { - - event.preventDefault(); - /* - const proxyStrings = splitBySemi(that.props.proxyStringRaw); - proxyStrings.splice(index, 1); - */ - const newVal = that.props.proxyStringRaw.replace( - new RegExp(`${proxyAsString}(?:\s*;\s*)*`, 'g'), - '' - ); - that.props.setProxyStringRaw( newVal ); - - } - - raisePriority(that, {proxyAsString, index}) { - - event.preventDefault(); - if (index < 1) { - return; - } - - const proxyStrs = splitBySemi(that.props.proxyStringRaw); - const target = proxyStrs[index - 1]; - const newVal = that.props.proxyStringRaw - .replace(proxyAsString, target) - .replace(target, proxyAsString); - - //proxyStrings.splice(index - 1, 2, proxyStrings[index], proxyStrings[index-1]); - - that.props.setProxyStringRaw( newVal ); - - } - - handleSubmit(that, event) { - - event.preventDefault(); - that.handleAdd(that, event); - - } - - render(props) { - - return ( -
- ); - } - } - - const getInitState = () => ({ - ifHasErrors: false, - stashedExports: false, - }); - - class ExportsEditor extends Component { - - constructor(props) { - - super(props); - this.state = getInitState(); - - } - - resetState(that, event) { - - that.setState(getInitState()); - event.preventDefault(); - - } - - getErrorsInStashedExports() { - - if(this.state.stashedExports === false) { - return; - } - const errors = splitBySemi(this.state.stashedExports) - .map((proxyAsString) => { - - const [rawType, addr, ...rest] = proxyAsString.split(/\s+/); - if (rest && rest.length) { - return new Error( - `"${rest.join(', ')}" кажется мне лишним. Вы забыли ";"?` - ); - } - 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; - - } - - handleModeSwitch(that, event) { - - if (that.state.stashedExports !== false) { - const errors = that.getErrorsInStashedExports(); - if (errors) { - that.setState({ifHasErrors: true}); - that.props.funs.showErrors(...errors); - return; - } - that.props.setProxyStringRaw(that.state.stashedExports); - } - that.setState({ - stashedExports: false, - ifHasErrors: false, - }); - that.props.onSwitch(); - - } - - handleTextareaChange(that, event) { - - that.setState({ - stashedExports: event.target.value, - }); - - } - - handleSubmit(that, event) { - - event.preventDefault(); - this.handleModeSwitch(this, event); - - } - - render(props) { - - const reset = linkEvent(this, this.resetState); - - return ( - - ); - - } - - } - - return class ProxyEditor extends Component { - - constructor(props) { - - super(props); - this.state = { - proxyStringRaw: localStorage.getItem(UI_RAW) || '', - ifExportsMode: false, - }; - this.handleSwitch = () => this.setState({ifExportsMode: !this.state.ifExportsMode}); - - } - - preventLostOfChanges() { - - window.onbeforeunload = () => true; // TODO - - } - - render(originalProps) { - - const props = Object.assign({ - proxyStringRaw: this.state.proxyStringRaw, - onSwitch: this.handleSwitch, - setProxyStringRaw: (newVal) => this.setState({proxyStringRaw: newVal}), - }, originalProps); - - return this.state.ifExportsMode - ? createElement(ExportsEditor, props) - : createElement(TabledEditor, props); - - }; - } - -};