mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
internationalization
This commit is contained in:
@@ -300,6 +300,10 @@ impl ConnectionManager {
|
||||
fn exit(&self) {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
fn t(&self, name: String) -> String {
|
||||
crate::client::translate(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl sciter::EventHandler for ConnectionManager {
|
||||
@@ -308,6 +312,7 @@ impl sciter::EventHandler for ConnectionManager {
|
||||
}
|
||||
|
||||
sciter::dispatch_script_call! {
|
||||
fn t(String);
|
||||
fn get_icon();
|
||||
fn close(i32);
|
||||
fn authorize(i32);
|
||||
|
||||
@@ -33,22 +33,22 @@ class Body: Reactor.Component
|
||||
<div>
|
||||
<div .id style="font-weight: bold; font-size: 1.2em;">{c.name}</div>
|
||||
<div .id>({c.peer_id})</div>
|
||||
<div style="margin-top: 1.2em">Connected <span #time>{getElaspsed(c.time)}</span></div>
|
||||
<div style="margin-top: 1.2em">{translate('Connected')} {" "} <span #time>{getElaspsed(c.time)}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
{c.is_file_transfer || c.port_forward ? "" : <div>Permissions</div>}
|
||||
{c.is_file_transfer || c.port_forward ? "" : <div>{translate('Permissions')}</div>}
|
||||
{c.is_file_transfer || c.port_forward ? "" : <div .permissions>
|
||||
<div class={!c.keyboard ? "disabled" : ""} title="Allow using keyboard and mouse"><icon .keyboard /></div>
|
||||
<div class={!c.clipboard ? "disabled" : ""} title="Allow using clipboard"><icon .clipboard /></div>
|
||||
<div class={!c.audio ? "disabled" : ""} title="Allow hearing sound"><icon .audio /></div>
|
||||
<div class={!c.keyboard ? "disabled" : ""} title={translate('Allow using keyboard and mouse')}><icon .keyboard /></div>
|
||||
<div class={!c.clipboard ? "disabled" : ""} title={translate('Allow using clipboard')}><icon .clipboard /></div>
|
||||
<div class={!c.audio ? "disabled" : ""} title={translate('Allow hearing sound')}><icon .audio /></div>
|
||||
</div>}
|
||||
{c.port_forward ? <div>Port Forwarding: {c.port_forward}</div> : ""}
|
||||
<div style="size:*"/>
|
||||
<div .buttons>
|
||||
{auth ? "" : <button .button tabindex="-1" #accept>Accept</button>}
|
||||
{auth ? "" : <button .button tabindex="-1" .outline #dismiss>Dismiss</button>}
|
||||
{auth ? <button .button tabindex="-1" #disconnect>Disconnect</button> : ""}
|
||||
{auth ? "" : <button .button tabindex="-1" #accept>{translate('Accept')}</button>}
|
||||
{auth ? "" : <button .button tabindex="-1" .outline #dismiss>{translate('Dismiss')}</button>}
|
||||
{auth ? <button .button tabindex="-1" #disconnect>{translate('Disconnect')}</button> : ""}
|
||||
</div>
|
||||
{c.is_file_transfer || c.port_forward ? "" : <div .chaticon>{svg_chat}</div>}
|
||||
</div>
|
||||
@@ -101,6 +101,7 @@ class Body: Reactor.Component
|
||||
connection.authorized = true;
|
||||
body.update();
|
||||
handler.authorize(cid);
|
||||
view.windowState = View.WINDOW_MINIMIZED;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,15 @@ var is_file_transfer;
|
||||
var is_xfce = false;
|
||||
try { is_xfce = handler.is_xfce(); } catch(e) {}
|
||||
|
||||
|
||||
function translate(name) {
|
||||
try {
|
||||
return handler.t(name);
|
||||
} catch(_) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
function hashCode(str) {
|
||||
var hash = 160 << 16 + 114 << 8 + 91;
|
||||
for (var i = 0; i < str.length; i += 1) {
|
||||
@@ -207,7 +216,7 @@ function getMsgboxParams() {
|
||||
return msgbox_params;
|
||||
}
|
||||
|
||||
function msgbox(type, title, text, callback, height, width, retry=0) {
|
||||
function msgbox(type, title, text, callback, height, width, retry=0, contentStyle="") {
|
||||
var has_msgbox = msgbox_params != null;
|
||||
if (!has_msgbox && !type) return;
|
||||
var remember = false;
|
||||
@@ -217,7 +226,8 @@ function msgbox(type, title, text, callback, height, width, retry=0) {
|
||||
msgbox_params = {
|
||||
remember: remember, type: type, text: text, title: title,
|
||||
getParams: getMsgboxParams,
|
||||
callback: callback, retry: retry,
|
||||
callback: callback, translate: translate,
|
||||
retry: retry, contentStyle: contentStyle,
|
||||
};
|
||||
if (has_msgbox) return;
|
||||
var dialog = {
|
||||
@@ -239,7 +249,7 @@ function msgbox(type, title, text, callback, height, width, retry=0) {
|
||||
} else if (res == "!alive") {
|
||||
// do nothing
|
||||
} else if (res.type == "input-password") {
|
||||
if (!is_port_forward) connecting();
|
||||
if (!is_port_forward) handler.msgbox("connecting", "Connecting...", "Logging in...");
|
||||
handler.login(res.password, res.remember);
|
||||
} else if (res.reconnect) {
|
||||
if (!is_port_forward) connecting();
|
||||
@@ -251,10 +261,10 @@ function connecting() {
|
||||
handler.msgbox("connecting", "Connecting...", "Connection in progress. Please wait.");
|
||||
}
|
||||
|
||||
handler.msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0) {
|
||||
handler.msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0, contentStyle="") {
|
||||
// directly call view.Dialog from native may crash, add timer here, seem safe
|
||||
// too short time, msgbox won't get focus, per my test, 150 is almost minimun
|
||||
self.timer(150ms, function() { msgbox(type, title, text, callback, height, width, retry); });
|
||||
self.timer(150ms, function() { msgbox(type, title, text, callback, height, width, retry, contentStyle); });
|
||||
}
|
||||
|
||||
handler.block_msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0) {
|
||||
@@ -312,6 +322,47 @@ function Progress()
|
||||
this.value = "";
|
||||
}
|
||||
|
||||
var svg_eye_cross = <svg viewBox="0 -21 511.96 511">
|
||||
<path d="m506.68 261.88c7.043-16.984 7.043-36.461 0-53.461-41.621-100.4-140.03-165.27-250.71-165.27-46.484 0-90.797 11.453-129.64 32.191l-68.605-68.609c-8.3438-8.3398-21.824-8.3398-30.168 0-8.3398 8.3398-8.3398 21.824 0 30.164l271.49 271.49 86.484 86.488 68.676 68.672c4.1797 4.1797 9.6406 6.2695 15.102 6.2695 5.4609 0 10.922-2.0898 15.082-6.25 8.3438-8.3398 8.3438-21.824 0-30.164l-62.145-62.145c36.633-27.883 66.094-65.109 84.438-109.38zm-293.91-100.1c12.648-7.5742 27.391-11.969 43.199-11.969 47.062 0 85.332 38.273 85.332 85.336 0 15.805-4.3945 30.547-11.969 43.199z"/>
|
||||
<path d="m255.97 320.48c-47.062 0-85.336-38.273-85.336-85.332 0-3.0938 0.59766-6.0195 0.91797-9.0039l-106.15-106.16c-25.344 24.707-46.059 54.465-60.117 88.43-7.043 16.98-7.043 36.457 0 53.461 41.598 100.39 140.01 165.27 250.69 165.27 34.496 0 67.797-6.3164 98.559-18.027l-89.559-89.559c-2.9844 0.32031-5.9062 0.91797-9 0.91797z"/>
|
||||
</svg>;
|
||||
|
||||
class PasswordComponent: Reactor.Component {
|
||||
this var visible = false;
|
||||
this var value = '';
|
||||
this var name = 'password';
|
||||
|
||||
function this(params) {
|
||||
if (params && params.value) {
|
||||
this.value = params.value;
|
||||
}
|
||||
if (params && params.name) {
|
||||
this.name = params.name;
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
return <div .password>
|
||||
<input name={this.name} value={this.value} type={this.visible ? "text" : "password"} .outline-focus />
|
||||
{this.visible ? svg_eye_cross : svg_eye}
|
||||
</div>;
|
||||
}
|
||||
|
||||
event click $(svg) {
|
||||
var el = this.$(input);
|
||||
var value = el.value;
|
||||
var start = el.xcall(#selectionStart) || 0;
|
||||
var end = el.xcall(#selectionEnd);
|
||||
this.update({ visible: !this.visible });
|
||||
self.timer(30ms, function() {
|
||||
var el = this.$(input);
|
||||
view.focus = el;
|
||||
el.value = value;
|
||||
el.xcall(#setSelection, start, end);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function isReasonableSize(r) {
|
||||
var x = r[0];
|
||||
var y = r[1];
|
||||
|
||||
@@ -141,11 +141,11 @@ class JobTable: Reactor.Component {
|
||||
}
|
||||
|
||||
function getStatus(job) {
|
||||
if (!job.entries) return "Waiting";
|
||||
if (!job.entries) return translate("Waiting");
|
||||
var i = job.file_num + 1;
|
||||
var n = job.num_entries || job.entries.length;
|
||||
if (i > n) i = n;
|
||||
var res = i + ' / ' + n + " files";
|
||||
var res = i + ' / ' + n + " " + translate("files");
|
||||
if (job.total_size > 0) {
|
||||
var s = getSize(0, job.finished_size);
|
||||
if (s) s += " / ";
|
||||
@@ -155,7 +155,7 @@ class JobTable: Reactor.Component {
|
||||
var percent = job.total_size == 0 ? 100 : (100. * job.finished_size / job.total_size).toInteger(); // (100. * i / (n || 1)).toInteger();
|
||||
if (job.finished) percent = '100';
|
||||
if (percent) res += ", " + percent + "%";
|
||||
if (job.finished) res = "Finished " + res;
|
||||
if (job.finished) res = translate("Finished") + " " + res;
|
||||
if (job.speed) res += ", " + getSize(0, job.speed) + "/s";
|
||||
return res;
|
||||
}
|
||||
@@ -250,7 +250,7 @@ class FolderView : Reactor.Component {
|
||||
return <div .title>
|
||||
{svg_computer}
|
||||
<div .platform>{platformSvg(handler.get_platform(this.is_remote), "white")}</div>
|
||||
<div><span>{this.is_remote ? "Remote Computer" : "Local Computer"}</span></div>
|
||||
<div><span>{translate(this.is_remote ? "Remote Computer" : "Local Computer")}</span></div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ class FolderView : Reactor.Component {
|
||||
function renderOpBar() {
|
||||
if (this.is_remote) {
|
||||
return <div .toolbar .remote>
|
||||
<div .send .button>{svg_send}<span>Receive</span></div>
|
||||
<div .send .button>{svg_send}<span>{translate('Receive')}</span></div>
|
||||
<div .spacer></div>
|
||||
<div .add-folder .button>{svg_add_folder}</div>
|
||||
<div .trash .button>{svg_trash}</div>
|
||||
@@ -283,7 +283,7 @@ class FolderView : Reactor.Component {
|
||||
<div .add-folder .button>{svg_add_folder}</div>
|
||||
<div .trash .button>{svg_trash}</div>
|
||||
<div .spacer></div>
|
||||
<div .send .button><span>Send</span>{svg_send}</div>
|
||||
<div .send .button><span>{translate('Send')}</span>{svg_send}</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -308,14 +308,14 @@ class FolderView : Reactor.Component {
|
||||
var id = (this.is_remote ? "remote" : "local") + "-folder-view";
|
||||
return <table @{this.table} .folder-view .has_current id={id}>
|
||||
<thead>
|
||||
<tr><th></th><th .sortable>Name</th><th .sortable>Modified</th><th .sortable>Size</th></tr>
|
||||
<tr><th></th><th .sortable>{translate('Name')}</th><th .sortable>{translate('Modified')}</th><th .sortable>{translate('Size')}</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
<popup>
|
||||
<menu.context id={id}>
|
||||
<li #switch-hidden class={this.show_hidden ? "selected" : ""}><span>{svg_checkmark}</span>Show Hidden Files</li>
|
||||
<li #switch-hidden class={this.show_hidden ? "selected" : ""}><span>{svg_checkmark}</span>{translate('Show Hidden Files')}</li>
|
||||
</menu>
|
||||
</popup>
|
||||
</table>;
|
||||
@@ -431,8 +431,8 @@ class FolderView : Reactor.Component {
|
||||
|
||||
event click $(.add-folder) () {
|
||||
var me = this;
|
||||
handler.msgbox("custom", "Create Folder", "<div .form> \
|
||||
<div>Please enter the folder name:</div> \
|
||||
handler.msgbox("custom", translate("Create Folder"), "<div .form> \
|
||||
<div>" + translate("Please enter the folder name") + ":</div> \
|
||||
<div><input|text(name) .outline-focus /></div> \
|
||||
</div>", function(res=null) {
|
||||
if (!res) return;
|
||||
@@ -523,7 +523,7 @@ class FolderView : Reactor.Component {
|
||||
var file_transfer;
|
||||
|
||||
class FileTransfer: Reactor.Component {
|
||||
function this(params) {
|
||||
function this() {
|
||||
file_transfer = this;
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@ var create_dir_jobs = {}
|
||||
|
||||
function confirmDelete(path, is_remote) {
|
||||
handler.block_msgbox("custom-skip", "Confirm Delete", "<div .form> \
|
||||
<div>Are you sure you want to delete this file?</div> \
|
||||
<div>" + translate('Are you sure you want to delete this file?') + "</div> \
|
||||
<div.ellipsis style=\"font-weight: bold;\">" + path + "</div> \
|
||||
</div>", function(res=null) {
|
||||
if (res) {
|
||||
@@ -620,10 +620,10 @@ handler.confirmDeleteFiles = function(id, i, name) {
|
||||
var file_path = job.path;
|
||||
if (name) file_path += handler.get_path_sep(job.is_remote) + name;
|
||||
handler.block_msgbox("custom-skip", "Confirm Delete", "<div .form> \
|
||||
<div>Deleting #" + (i + 1) + " of " + n + " files.</div> \
|
||||
<div>Are you sure you want to delete this file?</div> \
|
||||
<div>" + translate('Deleting') + " #" + (i + 1) + " / " + n + " " + translate('files') + ".</div> \
|
||||
<div>" + translate('Are you sure you want to delete this file?') + "</div> \
|
||||
<div.ellipsis style=\"font-weight: bold;\" .text>" + name + "</div> \
|
||||
<div><button|checkbox(remember) {ts}>Do this for all conflicts</button></div> \
|
||||
<div><button|checkbox(remember) {ts}>" + translate('Do this for all conflicts') + "</button></div> \
|
||||
</div>", function(res=null) {
|
||||
if (!res) {
|
||||
jt.updateJobStatus(id, i - 1, "cancel");
|
||||
|
||||
@@ -31,6 +31,10 @@ if (is_linux) {
|
||||
}
|
||||
}
|
||||
|
||||
function get_id() {
|
||||
return handler.get_option('alias') || handler.get_id()
|
||||
}
|
||||
|
||||
function stateChanged() {
|
||||
stdout.println('state changed from ' + cur_window_state + ' -> ' + view.windowState);
|
||||
cur_window_state = view.windowState;
|
||||
@@ -58,7 +62,7 @@ var old_window_state = View.WINDOW_SHOWN;
|
||||
var input_blocked;
|
||||
|
||||
class Header: Reactor.Component {
|
||||
function this(params) {
|
||||
function this() {
|
||||
header = this;
|
||||
}
|
||||
|
||||
@@ -67,18 +71,18 @@ class Header: Reactor.Component {
|
||||
var title_conn;
|
||||
if (this.secure_connection && this.direct_connection) {
|
||||
icon_conn = svg_secure;
|
||||
title_conn = "Direct and secure connection";
|
||||
title_conn = translate("Direct and encrypted connection");
|
||||
} else if (this.secure_connection && !this.direct_connection) {
|
||||
icon_conn = svg_secure_relay;
|
||||
title_conn = "Relayed and secure connection";
|
||||
title_conn = translate("Relayed and encrypted connection");
|
||||
} else if (!this.secure_connection && this.direct_connection) {
|
||||
icon_conn = svg_insecure;
|
||||
title_conn = "Direct and insecure connection";
|
||||
title_conn = translate("Direct and unencrypted connection");
|
||||
} else {
|
||||
icon_conn = svg_insecure_relay;
|
||||
title_conn = "Relayed and insecure connection";
|
||||
title_conn = translate("Relayed and unencrypted connection");
|
||||
}
|
||||
var title = handler.get_id();
|
||||
var title = get_id();
|
||||
if (pi.hostname) title += "(" + pi.username + "@" + pi.hostname + ")";
|
||||
if ((pi.displays || []).length == 0) {
|
||||
return <div .ellipsis style="size:*;text-align:center;margin:*;">{title}</div>;
|
||||
@@ -89,14 +93,14 @@ class Header: Reactor.Component {
|
||||
</div>;
|
||||
});
|
||||
updateWindowToolbarPosition();
|
||||
var style = "flow: horizontal;";
|
||||
if (is_osx) style += "margin: *";
|
||||
var style = "flow:horizontal;";
|
||||
if (is_osx) style += "margin:*";
|
||||
self.timer(1ms, toggleMenuState);
|
||||
return <div style={style}>
|
||||
{is_osx || is_xfce ? "" : <span #fullscreen>{svg_fullscreen}</span>}
|
||||
<div #screens>
|
||||
<span #secure title={title_conn}>{icon_conn}</span>
|
||||
<div .remote-id>{handler.get_id()}</div>
|
||||
<div .remote-id>{get_id()}</div>
|
||||
<div style="flow:horizontal;border-spacing: 0.5em;">{screens}</div>
|
||||
{this.renderGlobalScreens()}
|
||||
</div>
|
||||
@@ -111,22 +115,22 @@ class Header: Reactor.Component {
|
||||
function renderDisplayPop() {
|
||||
return <popup>
|
||||
<menu.context #display-options>
|
||||
<li #adjust-window style="display:none">Adjust Window</li>
|
||||
<li #adjust-window style="display:none">{translate('Adjust Window')}</li>
|
||||
<div #adjust-window .separator style="display:none"/>
|
||||
<li #original type="view-style"><span>{svg_checkmark}</span>Original</li>
|
||||
<li #shrink type="view-style"><span>{svg_checkmark}</span>Shrink</li>
|
||||
<li #stretch type="view-style"><span>{svg_checkmark}</span>Stretch</li>
|
||||
<li #original type="view-style"><span>{svg_checkmark}</span>{translate('Original')}</li>
|
||||
<li #shrink type="view-style"><span>{svg_checkmark}</span>{translate('Shrink')}</li>
|
||||
<li #stretch type="view-style"><span>{svg_checkmark}</span>{translate('Stretch')}</li>
|
||||
<div .separator />
|
||||
<li #best type="image-quality"><span>{svg_checkmark}</span>Good image quality</li>
|
||||
<li #balanced type="image-quality"><span>{svg_checkmark}</span>Balanced</li>
|
||||
<li #low type="image-quality"><span>{svg_checkmark}</span>Optimize reaction time</li>
|
||||
<li #custom type="image-quality"><span>{svg_checkmark}</span>Custom</li>
|
||||
<li #best type="image-quality"><span>{svg_checkmark}</span>{translate('Good image quality')}</li>
|
||||
<li #balanced type="image-quality"><span>{svg_checkmark}</span>{translate('Balanced')}</li>
|
||||
<li #low type="image-quality"><span>{svg_checkmark}</span>{translate('Optimize reaction time')}</li>
|
||||
<li #custom type="image-quality"><span>{svg_checkmark}</span>{translate('Custom')}</li>
|
||||
<div .separator />
|
||||
<li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>Show remote cursor</li>
|
||||
{audio_enabled ? <li #disable-audio .toggle-option><span>{svg_checkmark}</span>Mute</li> : ""}
|
||||
{keyboard_enabled && clipboard_enabled ? <li #disable-clipboard .toggle-option><span>{svg_checkmark}</span>Disable clipboard</li> : ""}
|
||||
{keyboard_enabled ? <li #lock-after-session-end .toggle-option><span>{svg_checkmark}</span>Lock after session end</li> : ""}
|
||||
{false && pi.platform == "Windows" ? <li #privacy-mode .toggle-option><span>{svg_checkmark}</span>Privacy mode</li> : ""}
|
||||
<li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Show remote cursor')}</li>
|
||||
{audio_enabled ? <li #disable-audio .toggle-option><span>{svg_checkmark}</span>{translate('Mute')}</li> : ""}
|
||||
{keyboard_enabled && clipboard_enabled ? <li #disable-clipboard .toggle-option><span>{svg_checkmark}</span>{translate('Disable clipboard')}</li> : ""}
|
||||
{keyboard_enabled ? <li #lock-after-session-end .toggle-option><span>{svg_checkmark}</span>{translate('Lock after session end')}</li> : ""}
|
||||
{false && pi.platform == "Windows" ? <li #privacy-mode .toggle-option><span>{svg_checkmark}</span>{translate('Privacy mode')}</li> : ""}
|
||||
</menu>
|
||||
</popup>;
|
||||
}
|
||||
@@ -134,23 +138,20 @@ class Header: Reactor.Component {
|
||||
function renderActionPop() {
|
||||
return <popup>
|
||||
<menu.context #action-options>
|
||||
<li #transfer-file>Transfer File</li>
|
||||
<li #tunnel>TCP Tunneling</li>
|
||||
<li #transfer-file>{translate('Transfer File')}</li>
|
||||
<li #tunnel>{translate('TCP Tunneling')}</li>
|
||||
<div .separator />
|
||||
{keyboard_enabled && (pi.platform == "Linux" || pi.sas_enabled) ? <li #ctrl-alt-del>Insert Ctrl + Alt + Del</li> : ""}
|
||||
<li #ctrl-space>Insert Ctrl + Space</li>
|
||||
<li #alt-tab>Insert Alt + Tab</li>
|
||||
{false && <li #super-x>Insert Win/Super + ...</li>}
|
||||
{keyboard_enabled && (pi.platform == "Linux" || pi.sas_enabled) ? <li #ctrl-alt-del>{translate('Insert')} Ctrl + Alt + Del</li> : ""}
|
||||
<div .separator />
|
||||
{keyboard_enabled ? <li #lock-screen>Insert Lock</li> : ""}
|
||||
{keyboard_enabled ? <li #lock-screen>{translate('Insert Lock')}</li> : ""}
|
||||
{false && pi.platform == "Windows" ? <li #block-input>Block user input </li> : ""}
|
||||
{handler.support_refresh() ? <li #refresh>Refresh</li> : ""}
|
||||
{handler.support_refresh() ? <li #refresh>{translate('Refresh')}</li> : ""}
|
||||
</menu>
|
||||
</popup>;
|
||||
}
|
||||
|
||||
function renderGlobalScreens() {
|
||||
if (pi.displays.length < 2) return "";
|
||||
if (pi.displays.length < 3) return "";
|
||||
var x0 = 9999999;
|
||||
var y0 = 9999999;
|
||||
var x = -9999999;
|
||||
@@ -232,18 +233,6 @@ class Header: Reactor.Component {
|
||||
event click $(#ctrl-alt-del) {
|
||||
handler.ctrl_alt_del();
|
||||
}
|
||||
|
||||
event click $(#alt-tab) {
|
||||
handler.alt_tab();
|
||||
}
|
||||
|
||||
event click $(#ctrl-space) {
|
||||
handler.ctrl_space();
|
||||
}
|
||||
|
||||
event click $(#super-x) {
|
||||
handler.super_x();
|
||||
}
|
||||
|
||||
event click $(#lock-screen) {
|
||||
handler.lock_screen();
|
||||
@@ -289,8 +278,8 @@ function handle_custom_image_quality() {
|
||||
var bitrate0 = tmp[0] || 50;
|
||||
var quantizer0 = tmp.length > 1 ? tmp[1] : 100;
|
||||
handler.msgbox("custom", "Custom Image Quality", "<div .form> \
|
||||
<div><input type=\"hslider\" style=\"width: 66%\" name=\"bitrate\" max=\"100\" min=\"10\" value=\"" + bitrate0 + "\"/ buddy=\"bitrate-buddy\"><b #bitrate-buddy>x</b>% bitrate</div> \
|
||||
<div><input type=\"hslider\" style=\"width: 66%\" name=\"quantizer\" max=\"100\" min=\"0\" value=\"" + quantizer0 + "\"/ buddy=\"quantizer-buddy\"><b #quantizer-buddy>x</b>% quantizer</div> \
|
||||
<div><input type=\"hslider\" style=\"width: 50%\" name=\"bitrate\" max=\"100\" min=\"10\" value=\"" + bitrate0 + "\"/ buddy=\"bitrate-buddy\"><b #bitrate-buddy>x</b>% bitrate</div> \
|
||||
<div><input type=\"hslider\" style=\"width: 50%\" name=\"quantizer\" max=\"100\" min=\"0\" value=\"" + quantizer0 + "\"/ buddy=\"quantizer-buddy\"><b #quantizer-buddy>x</b>% quantizer</div> \
|
||||
</div>", function(res=null) {
|
||||
if (!res) return;
|
||||
if (!res.bitrate) return;
|
||||
|
||||
166
src/ui/index.tis
166
src/ui/index.tis
@@ -18,29 +18,35 @@ var svg_menu = <svg #menu viewBox="0 0 512 512">
|
||||
<circle cx="256" cy="64" r="64"/>
|
||||
</svg>;
|
||||
|
||||
var my_id = "";
|
||||
function get_id() {
|
||||
my_id = handler.get_id();
|
||||
return my_id;
|
||||
}
|
||||
|
||||
class ConnectStatus: Reactor.Component {
|
||||
function render() {
|
||||
return
|
||||
<div .connect-status>
|
||||
<span class={"connect-status-icon connect-status" + (service_stopped ? 0 : connect_status)} />
|
||||
{this.getConnectStatusStr()}
|
||||
{service_stopped ? <span class="link">Start Service</span> : ""}
|
||||
{service_stopped ? <span .link #start-service>{translate('Start Service')}</span> : ""}
|
||||
</div>;
|
||||
}
|
||||
|
||||
function getConnectStatusStr() {
|
||||
if (service_stopped) {
|
||||
return "Service is not running";
|
||||
return translate("Service is not running");
|
||||
} else if (connect_status == -1) {
|
||||
return "Not ready. Please check your connection";
|
||||
return translate('not_ready_status');
|
||||
} else if (connect_status == 0) {
|
||||
return "Connecting to the RustDesk network...";
|
||||
return translate('connecting_status');
|
||||
}
|
||||
return "Ready";
|
||||
return translate("Ready");
|
||||
}
|
||||
|
||||
event click $(.connect-status .link) () {
|
||||
handler.set_option("stop-service", "");
|
||||
event click $(#start-service) () {
|
||||
handler.set_option("stop-service", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +56,7 @@ class RecentSessions: Reactor.Component {
|
||||
if (sessions.length == 0) return <span />;
|
||||
sessions = sessions.map(this.getSession);
|
||||
return <div style="width: *">
|
||||
<div .recent-sessions-title>RECENT SESSIONS</div>
|
||||
<div .recent-sessions-title>{translate("Recent Sessions")}</div>
|
||||
<div .recent-sessions-content key={sessions.length}>
|
||||
{sessions}
|
||||
</div>
|
||||
@@ -126,7 +132,7 @@ function createNewConnect(id, type) {
|
||||
id = id.replace(/\s/g, "");
|
||||
app.remote_id.value = formatId(id);
|
||||
if (!id) return;
|
||||
if (id == handler.get_id()) {
|
||||
if (id == my_id) {
|
||||
handler.msgbox("custom-error", "Error", "You cannot connect to your own computer");
|
||||
return;
|
||||
}
|
||||
@@ -149,10 +155,10 @@ class AudioInputs: Reactor.Component {
|
||||
inputs = ["Mute"].concat(inputs);
|
||||
var me = this;
|
||||
self.timer(1ms, function() { me.toggleMenuState() });
|
||||
return <li>Audio Input
|
||||
return <li>{translate('Audio Input')}
|
||||
<menu #audio-input key={inputs.length}>
|
||||
{inputs.map(function(name) {
|
||||
return <li id={name}><span>{svg_checkmark}</span>{name}</li>;
|
||||
return <li id={name}><span>{svg_checkmark}</span>{translate(name)}</li>;
|
||||
})}
|
||||
</menu>
|
||||
</li>;
|
||||
@@ -190,7 +196,6 @@ class MyIdMenu: Reactor.Component {
|
||||
}
|
||||
|
||||
function render() {
|
||||
var me = this;
|
||||
return <div #myid>
|
||||
{this.renderPop()}
|
||||
ID{svg_menu}
|
||||
@@ -200,19 +205,18 @@ class MyIdMenu: Reactor.Component {
|
||||
function renderPop() {
|
||||
return <popup>
|
||||
<menu.context #config-options>
|
||||
<li #enable-keyboard><span>{svg_checkmark}</span>Enable Keyboard/Mouse</li>
|
||||
<li #enable-clipboard><span>{svg_checkmark}</span>Enable Clipboard</li>
|
||||
<li #enable-file-transfer><span>{svg_checkmark}</span>Enable File Transfer</li>
|
||||
<li #enable-tunnel><span>{svg_checkmark}</span>Enable TCP Tunneling</li>
|
||||
<li #enable-keyboard><span>{svg_checkmark}</span>{translate('Enable Keyboard/Mouse')}</li>
|
||||
<li #enable-clipboard><span>{svg_checkmark}</span>{translate('Enable Clipboard')}</li>
|
||||
<li #enable-file-transfer><span>{svg_checkmark}</span>{translate('Enable File Transfer')}</li>
|
||||
<li #enable-tunnel><span>{svg_checkmark}</span>{translate('Enable TCP Tunneling')}</li>
|
||||
<AudioInputs />
|
||||
<div .separator />
|
||||
<li #whitelist title="Only whitelisted IP can access me">IP Whitelisting</li>
|
||||
<li #custom-server>ID/Relay Server</li>
|
||||
<li #whitelist title={translate('whitelist_tip')}>{translate('IP Whitelisting')}</li>
|
||||
<li #custom-server>{translate('ID/Relay Server')}</li>
|
||||
<div .separator />
|
||||
<li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>Enable Service</li>
|
||||
<li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>{translate("Enable Service")}</li>
|
||||
<div .separator />
|
||||
<li #forum>Forum</li>
|
||||
<li #about>About {handler.get_app_name()}</li>
|
||||
<li #about>{translate('About')} {" "} {handler.get_app_name()}</li>
|
||||
</menu>
|
||||
</popup>;
|
||||
}
|
||||
@@ -240,8 +244,9 @@ class MyIdMenu: Reactor.Component {
|
||||
}
|
||||
if (me.id == "whitelist") {
|
||||
var old_value = handler.get_option("whitelist").split(",").join("\n");
|
||||
handler.msgbox("custom-whitelist", "IP Whitelisting", "<div .form> \
|
||||
<textarea spellcheck=\"false\" name=\"text\" novalue=\"0.0.0.0\" style=\"overflow: scroll-indicator; height: 160px; font-size: 1.2em; padding: 0.5em;\">" + old_value + "</textarea>\
|
||||
handler.msgbox("custom-whitelist", translate("IP Whitelisting"), "<div .form> \
|
||||
<div>" + translate("whitelist_sep") + "</div> \
|
||||
<textarea spellcheck=\"false\" name=\"text\" novalue=\"0.0.0.0\" style=\"overflow: scroll-indicator; width:*; height: 160px; font-size: 1.2em; padding: 0.5em;\">" + old_value + "</textarea>\
|
||||
</div> \
|
||||
", function(res=null) {
|
||||
if (!res) return;
|
||||
@@ -250,7 +255,7 @@ class MyIdMenu: Reactor.Component {
|
||||
var values = value.split(/[\s,;\n]+/g);
|
||||
for (var ip in values) {
|
||||
if (!ip.match(/^\d+\.\d+\.\d+\.\d+$/)) {
|
||||
return "Invalid ip: " + ip;
|
||||
return translate("Invalid IP") + ": " + ip;
|
||||
}
|
||||
}
|
||||
value = values.join("\n");
|
||||
@@ -260,12 +265,12 @@ class MyIdMenu: Reactor.Component {
|
||||
handler.set_option("whitelist", value.replace("\n", ","));
|
||||
}, 300);
|
||||
} else if (me.id == "custom-server") {
|
||||
var configOptions = handler.get_options();
|
||||
var configOptions = handler.get_options();
|
||||
var old_relay = configOptions["relay-server"] || "";
|
||||
var old_id = configOptions["custom-rendezvous-server"] || "";
|
||||
handler.msgbox("custom-server", "ID/Relay Server", "<div .form> \
|
||||
<div><span style='width: 100px; display:inline-block'>ID Server: </span><input style='width: 250px' name='id' value='" + old_id + "' /></div> \
|
||||
<div><span style='width: 100px; display:inline-block'>Relay Server: </span><input style='width: 250px' name='relay' value='" + old_relay + "' /></div> \
|
||||
<div><span style='width: 100px; display:inline-block'>" + translate("ID Server") + ": </span><input .outline-focus style='width: 250px' name='id' value='" + old_id + "' /></div> \
|
||||
<div><span style='width: 100px; display:inline-block'>" + translate("Relay Server") + ": </span><input style='width: 250px' name='relay' value='" + old_relay + "' /></div> \
|
||||
</div> \
|
||||
", function(res=null) {
|
||||
if (!res) return;
|
||||
@@ -274,18 +279,16 @@ class MyIdMenu: Reactor.Component {
|
||||
if (id == old_id && relay == old_relay) return;
|
||||
if (id) {
|
||||
var err = handler.test_if_valid_server(id);
|
||||
if (err) return "ID Server: " + err;
|
||||
if (err) return translate("ID Server") + ": " + err;
|
||||
}
|
||||
if (relay) {
|
||||
var err = handler.test_if_valid_server(relay);
|
||||
if (err) return "Relay Server: " + err;
|
||||
if (err) return translate("Relay Server") + ": " + err;
|
||||
}
|
||||
configOptions["custom-rendezvous-server"] = id;
|
||||
configOptions["relay-server"] = relay;
|
||||
handler.set_options(configOptions);
|
||||
});
|
||||
} else if (me.id == "forum") {
|
||||
handler.open_url("https:://forum.rustdesk.com");
|
||||
}, 240);
|
||||
} else if (me.id == "stop-service") {
|
||||
handler.set_option("stop-service", service_stopped ? "" : "Y");
|
||||
} else if (me.id == "about") {
|
||||
@@ -293,7 +296,7 @@ class MyIdMenu: Reactor.Component {
|
||||
handler.msgbox("custom-nocancel-nook-hasclose", "About " + name, "<div style='line-height: 2em'> \
|
||||
<div>Version: " + handler.get_version() + " \
|
||||
<div .link .custom-event url='http://rustdesk.com/privacy'>Privacy Statement</div> \
|
||||
<div .link .custom-event url='http://forum.rustdesk.com'>Forum</div> \
|
||||
<div .link .custom-event url='http://rustdesk.com'>Website</div> \
|
||||
<div style='background: #2c8cff; color: white; padding: 1em; margin-top: 1em;'>Copyright © 2020 CarrieZ Studio \
|
||||
<br /> Author: Carrie \
|
||||
<p style='font-weight: bold'>Made with heart in this chaotic world!</p>\
|
||||
@@ -319,13 +322,13 @@ class App: Reactor.Component
|
||||
<div .app>
|
||||
<popup>
|
||||
<menu.context #remote-context>
|
||||
<li #connect>Connect</li>
|
||||
<li #transfer>Transfer File</li>
|
||||
<li #tunnel>TCP Tunneling</li>
|
||||
<li #rdp>RDP</li>
|
||||
<li #rename>Rename</li>
|
||||
<li #remove>Remove</li>
|
||||
{is_win && <li #shortcut>Create Desktop Shortcut</li>}
|
||||
<li #connect>{translate('Connect')}</li>
|
||||
<li #transfer>{translate('Transfer File')}</li>
|
||||
<li #tunnel>{translate('TCP Tunneling')}</li>
|
||||
<li #rdp>RDP</li>
|
||||
<li #rename>{translate('Rename')}</li>
|
||||
<li #remove>{translate('Remove')}</li>
|
||||
{is_win && <li #shortcut>{translate('Create Desktop Shortcut')}</li>}
|
||||
</menu>
|
||||
</popup>
|
||||
<popup>
|
||||
@@ -336,18 +339,18 @@ class App: Reactor.Component
|
||||
</popup>
|
||||
<div .left-pane>
|
||||
<div>
|
||||
<div .title>Your Desktop</div>
|
||||
<div .lighter-text>Your desktop can be accessed with this ID and password.</div>
|
||||
<div .title>{translate('Your Desktop')}</div>
|
||||
<div .lighter-text>{translate('desk_tip')}</div>
|
||||
<div .your-desktop>
|
||||
<MyIdMenu />
|
||||
{key_confirmed ? <input type="text" readonly value={formatId(handler.get_id())}/> : "Generating ..."}
|
||||
<MyIdMenu />
|
||||
{key_confirmed ? <input type="text" readonly value={formatId(get_id())}/> : translate("Generating ...")}
|
||||
</div>
|
||||
<div .your-desktop>
|
||||
<div>Password</div>
|
||||
<div>{translate('Password')}</div>
|
||||
<Password />
|
||||
</div>
|
||||
</div>
|
||||
{handler.is_installed() ? "": <InstalllMe />}
|
||||
{handler.is_installed() ? "": <InstallMe />}
|
||||
{handler.is_installed() && software_update_url ? <UpdateMe /> : ""}
|
||||
{handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? <UpgradeMe /> : ""}
|
||||
{is_can_screen_recording ? "": <CanScreenRecording />}
|
||||
@@ -359,11 +362,11 @@ class App: Reactor.Component
|
||||
<div .right-pane>
|
||||
<div .right-content>
|
||||
<div .card-connect>
|
||||
<div .title>Control Remote Desktop</div>
|
||||
<div .title>{translate('Control Remote Desktop')}</div>
|
||||
<ID @{this.remote_id} />
|
||||
<div .right-buttons>
|
||||
<button .button .outline #file-transfer>Transfer File</button>
|
||||
<button .button #connect>Connect</button>
|
||||
<button .button .outline #file-transfer>{translate('Transfer File')}</button>
|
||||
<button .button #connect>{translate('Connect')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<RecentSessions @{this.recent_sessions} />
|
||||
@@ -386,11 +389,12 @@ class App: Reactor.Component
|
||||
}
|
||||
}
|
||||
|
||||
class InstalllMe: Reactor.Component {
|
||||
class InstallMe: Reactor.Component {
|
||||
function render() {
|
||||
return <div .install-me>
|
||||
<div>Install RustDesk</div>
|
||||
<div #install-me .link>Install RustDesk on this computer ...</div>
|
||||
<span />
|
||||
<div>{translate('install_tip')}</div>
|
||||
<button #install-me .button>{translate('Install')}</button>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -445,9 +449,9 @@ class UpgradeMe: Reactor.Component {
|
||||
function render() {
|
||||
var update_or_download = is_osx ? "download" : "update";
|
||||
return <div .install-me>
|
||||
<div>{handler.get_app_name()} Status</div>
|
||||
<div>An update is available for RustDesk.</div>
|
||||
<div #install-me .link style="padding-top: 1em">Click to upgrade</div>
|
||||
<div>{translate('Status')}</div>
|
||||
<div>{translate('Your installation is lower version.')}</div>
|
||||
<div #install-me .link style="padding-top: 1em">{translate('Click to upgrade')}</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -458,9 +462,9 @@ class UpgradeMe: Reactor.Component {
|
||||
|
||||
class UpdateMe: Reactor.Component {
|
||||
function render() {
|
||||
var update_or_download = is_osx ? "download" : "update";
|
||||
var update_or_download = "download"; // !is_win ? "download" : "update";
|
||||
return <div .install-me>
|
||||
<div>{handler.get_app_name()} Status</div>
|
||||
<div>{translate('Status')}</div>
|
||||
<div>There is a newer version of {handler.get_app_name()} ({handler.get_new_version()}) available.</div>
|
||||
<div #install-me .link style="padding-top: 1em">Click to {update_or_download}</div>
|
||||
<div #download-percent style="display:hidden; padding-top: 1em;" />
|
||||
@@ -468,14 +472,16 @@ class UpdateMe: Reactor.Component {
|
||||
}
|
||||
|
||||
event click $(#install-me) {
|
||||
if (is_osx) {
|
||||
handler.open_url("https://rustdesk.com");
|
||||
return;
|
||||
if (!is_win) {
|
||||
handler.open_url("https://rustdesk.com");
|
||||
return;
|
||||
}
|
||||
var url = software_update_url + '.' + handler.get_software_ext();
|
||||
var path = handler.get_software_store_path();
|
||||
var onsuccess = function(md5) {
|
||||
$(#download-percent).content("Installing ...");
|
||||
$(#download-percent).content(translate("Installing ..."));
|
||||
handler.update_me(path);
|
||||
};
|
||||
var onerror = function(err) {
|
||||
@@ -506,9 +512,9 @@ class SystemError: Reactor.Component {
|
||||
class TrustMe: Reactor.Component {
|
||||
function render() {
|
||||
return <div .trust-me>
|
||||
<div>Configuration Permissions</div>
|
||||
<div>In order to control your Desktop remotely, you need to grant RustDesk "Accessibility" permissions</div>
|
||||
<div #trust-me .link>Configure</div>
|
||||
<div>{translate('Configuration Permissions')}</div>
|
||||
<div>{translate('config_acc')}</div>
|
||||
<div #trust-me .link>{translate('Configure')}</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -521,9 +527,9 @@ class TrustMe: Reactor.Component {
|
||||
class CanScreenRecording: Reactor.Component {
|
||||
function render() {
|
||||
return <div .trust-me>
|
||||
<div>Configuration Permissions</div>
|
||||
<div>In order to access your Desktop remotely, you need to grant RustDesk "Screen Recording" permissions</div>
|
||||
<div #screen-recording .link>Configure</div>
|
||||
<div>{translate('Configuration Permissions')}</div>
|
||||
<div>{translate('config_screen')}</div>
|
||||
<div #screen-recording .link>{translate('Configure')}</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -536,9 +542,10 @@ class CanScreenRecording: Reactor.Component {
|
||||
class FixWayland: Reactor.Component {
|
||||
function render() {
|
||||
return <div .trust-me>
|
||||
<div>Warning</div>
|
||||
<div>Login screen using Wayland is not supported</div>
|
||||
<div #fix-wayland .link>Fix it</div>
|
||||
<div>{translate('Warning')}</div>
|
||||
<div>{translate('Login screen using Wayland is not supported')}</div>
|
||||
<div #fix-wayland .link>{translate('Fix it')}</div>
|
||||
<div style="text-align: center">({translate('Reboot required')})</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -551,9 +558,10 @@ class FixWayland: Reactor.Component {
|
||||
class ModifyDefaultLogin: Reactor.Component {
|
||||
function render() {
|
||||
return <div .trust-me>
|
||||
<div>Warning</div>
|
||||
<div>Current Wayland display server is not supported</div>
|
||||
<div #modify-default-login .link>Fix it(re-login required)</div>
|
||||
<div>{translate('Warning')}</div>
|
||||
<div>{translate('Current Wayland display server is not supported')}</div>
|
||||
<div #modify-default-login .link>{translate('Fix it')}</div>
|
||||
<div style="text-align: center">({translate('Reboot required')})</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -622,19 +630,19 @@ class Password: Reactor.Component {
|
||||
|
||||
event click $(li#set-password) {
|
||||
var me = this;
|
||||
handler.msgbox("custom-password", "Set Password", "<div .form .set-password> \
|
||||
<div><span>Password:</span><input|password(password) /></div> \
|
||||
<div><span>Confirmation:</span><input|password(confirmation) /></div> \
|
||||
handler.msgbox("custom-password", translate("Set Password"), "<div .form .set-password> \
|
||||
<div><span>" + translate('Password') + ":</span><input|password(password) .outline-focus /></div> \
|
||||
<div><span>" + translate('Confirmation') + ":</span><input|password(confirmation) /></div> \
|
||||
</div> \
|
||||
", function(res=null) {
|
||||
if (!res) return;
|
||||
var p0 = (res.password || "").trim();
|
||||
var p1 = (res.confirmation || "").trim();
|
||||
if (p0.length < 6) {
|
||||
return "Too short, at least 6 characters.";
|
||||
return translate("Too short, at least 6 characters.");
|
||||
}
|
||||
if (p0 != p1) {
|
||||
return "The confirmation is not identical.";
|
||||
return translate("The confirmation is not identical.");
|
||||
}
|
||||
handler.update_password(p0);
|
||||
me.update();
|
||||
@@ -644,7 +652,7 @@ class Password: Reactor.Component {
|
||||
|
||||
class ID: Reactor.Component {
|
||||
function render() {
|
||||
return <input type="text" #remote_id .outline-focus novalue="Enter Remote ID" maxlength="13"
|
||||
return <input type="text" #remote_id .outline-focus novalue={translate("Enter Remote ID")} maxlength="15"
|
||||
value={formatId(handler.get_remote_id())} />;
|
||||
}
|
||||
|
||||
@@ -735,6 +743,10 @@ function checkConnectStatus() {
|
||||
key_confirmed = tmp[1];
|
||||
app.update();
|
||||
}
|
||||
if (tmp[2] && tmp[2] != my_id) {
|
||||
stdout.println("id updated");
|
||||
app.update();
|
||||
}
|
||||
tmp = handler.get_error();
|
||||
if (system_error != tmp) {
|
||||
system_error = tmp;
|
||||
|
||||
@@ -5,17 +5,17 @@ function self.ready() {
|
||||
class Install: Reactor.Component {
|
||||
function render() {
|
||||
return <div .content>
|
||||
<div style="font-size: 2em;">Installation</div>
|
||||
<div style="margin: 2em 0;">Installation Path: <input|text disabled value={view.install_path()} /></div>
|
||||
<div><button|checkbox #startmenu checked>Create start menu shortcuts</button></div>
|
||||
<div><button|checkbox #desktopicon checked>Create desktop icon</button></div>
|
||||
<div #aggrement .link style="margin-top: 2em;">End-user license agreement</div>
|
||||
<div>By starting the installation, you accept the license agreement.</div>
|
||||
<div style="font-size: 2em;">{translate('Installation')}</div>
|
||||
<div style="margin: 2em 0;">{translate('Installation Path')} {": "}<input|text disabled value={view.install_path()} /></div>
|
||||
<div><button|checkbox #startmenu checked>{translate('Create start menu shortcuts')}</button></div>
|
||||
<div><button|checkbox #desktopicon checked>{translate('Create desktop icon')}</button></div>
|
||||
<div #aggrement .link style="margin-top: 2em;">{translate('End-user license agreement')}</div>
|
||||
<div>{translate('agreement_tip')}</div>
|
||||
<div style="height: 1px; background: gray; margin-top: 1em" />
|
||||
<div style="text-align: right;">
|
||||
<progress style={"color:" + color} style="display: none" />
|
||||
<button .button id="cancel" .outline style="margin-right: 2em;">Cancel</button>
|
||||
<button .button id="submit">Accept and Install</button>
|
||||
<button .button id="cancel" .outline style="margin-right: 2em;">{translate('Cancel')}</button>
|
||||
<button .button id="submit">{translate('Accept and Install')}</button>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
@@ -42,4 +42,4 @@ class Install: Reactor.Component {
|
||||
}
|
||||
}
|
||||
|
||||
$(body).content(<Install />);
|
||||
$(body).content(<Install />);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var type, title, text, getParams, remember, retry, callback;
|
||||
var type, title, text, getParams, remember, retry, callback, contentStyle;
|
||||
var my_translate;
|
||||
|
||||
function updateParams(params) {
|
||||
type = params.type;
|
||||
@@ -7,7 +8,10 @@ function updateParams(params) {
|
||||
getParams = params.getParams;
|
||||
remember = params.remember;
|
||||
callback = params.callback;
|
||||
my_translate = params.translate;
|
||||
retry = params.retry;
|
||||
contentStyle = params.contentStyle;
|
||||
try { text = translate_text(text); } catch (e) {}
|
||||
if (retry > 0) {
|
||||
self.timer(retry * 1000, function() {
|
||||
view.close({ reconnect: true });
|
||||
@@ -15,39 +19,20 @@ function updateParams(params) {
|
||||
}
|
||||
}
|
||||
|
||||
function translate_text(text) {
|
||||
if (text.indexOf('Failed') == 0 && text.indexOf(': ') > 0) {
|
||||
var fds = text.split(': ');
|
||||
for (var i = 0; i < fds.length; ++i) {
|
||||
fds[i] = my_translate(fds[i]);
|
||||
}
|
||||
text = fds.join(': ');
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
var params = view.parameters;
|
||||
updateParams(params);
|
||||
|
||||
var svg_eye_cross = <svg viewBox="0 -21 511.96 511">
|
||||
<path d="m506.68 261.88c7.043-16.984 7.043-36.461 0-53.461-41.621-100.4-140.03-165.27-250.71-165.27-46.484 0-90.797 11.453-129.64 32.191l-68.605-68.609c-8.3438-8.3398-21.824-8.3398-30.168 0-8.3398 8.3398-8.3398 21.824 0 30.164l271.49 271.49 86.484 86.488 68.676 68.672c4.1797 4.1797 9.6406 6.2695 15.102 6.2695 5.4609 0 10.922-2.0898 15.082-6.25 8.3438-8.3398 8.3438-21.824 0-30.164l-62.145-62.145c36.633-27.883 66.094-65.109 84.438-109.38zm-293.91-100.1c12.648-7.5742 27.391-11.969 43.199-11.969 47.062 0 85.332 38.273 85.332 85.336 0 15.805-4.3945 30.547-11.969 43.199z"/>
|
||||
<path d="m255.97 320.48c-47.062 0-85.336-38.273-85.336-85.332 0-3.0938 0.59766-6.0195 0.91797-9.0039l-106.15-106.16c-25.344 24.707-46.059 54.465-60.117 88.43-7.043 16.98-7.043 36.457 0 53.461 41.598 100.39 140.01 165.27 250.69 165.27 34.496 0 67.797-6.3164 98.559-18.027l-89.559-89.559c-2.9844 0.32031-5.9062 0.91797-9 0.91797z"/>
|
||||
</svg>;
|
||||
|
||||
class Password: Reactor.Component {
|
||||
this var visible = false;
|
||||
|
||||
function render() {
|
||||
return <div .password>
|
||||
<input name="password" type={this.visible ? "text" : "password"} .outline-focus />
|
||||
{this.visible ? svg_eye_cross : svg_eye}
|
||||
</div>;
|
||||
}
|
||||
|
||||
event click $(svg) {
|
||||
var el = this.$(input);
|
||||
var value = el.value;
|
||||
var start = el.xcall(#selectionStart) || 0;
|
||||
var end = el.xcall(#selectionEnd);
|
||||
this.update({ visible: !this.visible });
|
||||
self.timer(30ms, function() {
|
||||
var el = this.$(input);
|
||||
view.focus = el;
|
||||
el.value = value;
|
||||
el.xcall(#setSelection, start, end);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var body;
|
||||
|
||||
class Body: Reactor.Component {
|
||||
@@ -74,9 +59,9 @@ class Body: Reactor.Component {
|
||||
function getInputPasswordContent() {
|
||||
var ts = remember ? { checked: true } : {};
|
||||
return <div .form>
|
||||
<div>Please enter your password</div>
|
||||
<Password />
|
||||
<div><button|checkbox(remember) {ts}>Remember password</button></div>
|
||||
<div>{my_translate('Please enter your password')}</div>
|
||||
<PasswordComponent />
|
||||
<div><button|checkbox(remember) {ts}>{my_translate('Remember password')}</button></div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -116,27 +101,27 @@ class Body: Reactor.Component {
|
||||
var me = this;
|
||||
self.timer(1ms, function() {
|
||||
if (typeof content == "string")
|
||||
me.$(#content).html = content;
|
||||
me.$(#content).html = my_translate(content);
|
||||
else
|
||||
me.$(#content).content(content);
|
||||
});
|
||||
return (
|
||||
<div style="size: *">
|
||||
<header style={"height: 2em; background: " + color}>
|
||||
<caption role="window-caption">{title}</caption>
|
||||
<caption role="window-caption">{my_translate(title)}</caption>
|
||||
</header>
|
||||
<div style="padding: 1em 2em; size: *;">
|
||||
<div style="height: *; flow: horizontal">
|
||||
{icon && <div style="height: *; margin: * 0; padding-right: 2em;">{icon}</div>}
|
||||
<div style="size: *; margin: * 0;" #content />
|
||||
<div style={contentStyle || "size: *; margin: * 0;"} #content />
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<span #error />
|
||||
{show_progress ? <progress style={"color:" + color} /> : ""}
|
||||
{hasCancel || hasRetry ? <button .button #cancel .outline>{hasRetry ? "OK" : "Cancel"}</button> : ""}
|
||||
{this.hasSkip() ? <button .button #skip .outline>Skip</button> : ""}
|
||||
{hasOk || hasRetry ? <button .button #submit>{hasRetry ? "Retry" : "OK"}</button> : ""}
|
||||
{hasClose ? <button .button #cancel .outline>Close</button> : ""}
|
||||
<span style="display:inline-block; max-width: 260px; font-size:12px;" #error />
|
||||
<progress #progress style={"color:" + color + "; display: " + (show_progress ? "inline-block" : "none")} />
|
||||
{hasCancel || hasRetry ? <button .button #cancel .outline>{my_translate(hasRetry ? "OK" : "Cancel")}</button> : ""}
|
||||
{this.hasSkip() ? <button .button #skip .outline>{my_translate('Skip')}</button> : ""}
|
||||
{hasOk || hasRetry ? <button .button #submit>{my_translate(hasRetry ? "Retry" : "OK")}</button> : ""}
|
||||
{hasClose ? <button .button #cancel .outline>{my_translate('Close')}</button> : ""}
|
||||
</div>
|
||||
</div>
|
||||
</div>);
|
||||
@@ -149,6 +134,17 @@ class Body: Reactor.Component {
|
||||
|
||||
$(body).content(<Body />);
|
||||
|
||||
function show_progress(show=1, err="") {
|
||||
if (show == -1) {
|
||||
view.close()
|
||||
return;
|
||||
}
|
||||
$(#progress).style.set {
|
||||
display: show ? "inline-block" : "none"
|
||||
};
|
||||
$(#error).text = err;
|
||||
}
|
||||
|
||||
function submit() {
|
||||
if ($(button#submit)) {
|
||||
$(button#submit).sendEvent("click");
|
||||
@@ -211,9 +207,12 @@ event click $(button#submit) {
|
||||
}
|
||||
var values = getValues();
|
||||
if (callback) {
|
||||
var err = callback(values);
|
||||
var err = callback(values, show_progress);
|
||||
if (err && !err.trim()) {
|
||||
return;
|
||||
}
|
||||
if (err) {
|
||||
$(#error).text = err;
|
||||
show_progress(false, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -235,7 +234,7 @@ event keydown (evt) {
|
||||
|
||||
function set_outline_focus() {
|
||||
self.timer(30ms, function() {
|
||||
var el = $(input.outline-focus);
|
||||
var el = $(.outline-focus);
|
||||
if (el) view.focus = el;
|
||||
else {
|
||||
el = $(#submit);
|
||||
|
||||
@@ -21,17 +21,17 @@ class PortForward: Reactor.Component {
|
||||
});
|
||||
return <div #file-transfer><section>
|
||||
{pfs.length ? <div style="background: green; color: white; text-align: center; padding: 0.5em;">
|
||||
<span style="font-size: 1.2em">Listening ...</span><br/>
|
||||
<span style="font-size: 0.8em; color: #ddd">Don't close this window while you are using the tunnel</span>
|
||||
<span style="font-size: 1.2em">{translate('Listening ...')}</span><br/>
|
||||
<span style="font-size: 0.8em; color: #ddd">{translate('not_close_tcp_tip')}</span>
|
||||
</div> : ""}
|
||||
<table #port-forward>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Local Port</th>
|
||||
<th>{translate('Local Port')}</th>
|
||||
<th style="width: 1em" />
|
||||
<th>Remote Host</th>
|
||||
<th>Remote Port</th>
|
||||
{args.length ? "" : <th style="width: 6em">Action</th>}
|
||||
<th>{translate('Remote Host')}</th>
|
||||
<th>{translate('Remote Port')}</th>
|
||||
{args.length ? "" : <th style="width: 6em">{translate('Action')}</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody key={pfs.length}>
|
||||
@@ -41,7 +41,7 @@ class PortForward: Reactor.Component {
|
||||
<td .right-arrow style="text-align: center">{svg_arrow}</td>
|
||||
<td><input|text #remote-host novalue="localhost" /></td>
|
||||
<td><input|number #remote-port /></td>
|
||||
<td style="margin:0;"><button .button #add>Add</button></td>
|
||||
<td style="margin:0;"><button .button #add>{translate('Add')}</button></td>
|
||||
</tr>
|
||||
}
|
||||
{pfs}
|
||||
|
||||
@@ -54,7 +54,6 @@ pub struct HandlerInner {
|
||||
sender: Option<mpsc::UnboundedSender<Data>>,
|
||||
thread: Option<std::thread::JoinHandle<()>>,
|
||||
close_state: HashMap<String, String>,
|
||||
last_down_key: Option<(String, i32, bool)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
@@ -64,7 +63,6 @@ pub struct Handler {
|
||||
id: String,
|
||||
args: Vec<String>,
|
||||
lc: Arc<RwLock<LoginConfigHandler>>,
|
||||
super_on: bool,
|
||||
}
|
||||
|
||||
impl Deref for Handler {
|
||||
@@ -146,6 +144,8 @@ impl sciter::EventHandler for Handler {
|
||||
fn get_id();
|
||||
fn get_default_pi();
|
||||
fn get_option(String);
|
||||
fn t(String);
|
||||
fn set_option(String, String);
|
||||
fn save_close_state(String, String);
|
||||
fn is_file_transfer();
|
||||
fn is_port_forward();
|
||||
@@ -155,9 +155,6 @@ impl sciter::EventHandler for Handler {
|
||||
fn send_mouse(i32, i32, i32, bool, bool, bool, bool);
|
||||
fn key_down_or_up(bool, String, i32, bool, bool, bool, bool, bool);
|
||||
fn ctrl_alt_del();
|
||||
fn ctrl_space();
|
||||
fn alt_tab();
|
||||
fn super_x();
|
||||
fn transfer_file();
|
||||
fn tunnel();
|
||||
fn lock_screen();
|
||||
@@ -286,6 +283,10 @@ impl Handler {
|
||||
self.lc.read().unwrap().remember
|
||||
}
|
||||
|
||||
fn t(&self, name: String) -> String {
|
||||
crate::client::translate(name)
|
||||
}
|
||||
|
||||
fn is_xfce(&self) -> bool {
|
||||
crate::platform::is_xfce()
|
||||
}
|
||||
@@ -408,6 +409,10 @@ impl Handler {
|
||||
self.lc.read().unwrap().get_option(&k)
|
||||
}
|
||||
|
||||
fn set_option(&self, k: String, v: String) {
|
||||
self.lc.write().unwrap().set_option(k, v);
|
||||
}
|
||||
|
||||
fn save_close_state(&self, k: String, v: String) {
|
||||
self.write().unwrap().close_state.insert(k, v);
|
||||
}
|
||||
@@ -534,7 +539,6 @@ impl Handler {
|
||||
fn reconnect(&mut self) {
|
||||
let cloned = self.clone();
|
||||
let mut lock = self.write().unwrap();
|
||||
lock.last_down_key.take();
|
||||
lock.thread.take().map(|t| t.join());
|
||||
lock.thread = Some(std::thread::spawn(move || {
|
||||
io_loop(cloned);
|
||||
@@ -667,7 +671,6 @@ impl Handler {
|
||||
let evt_type = mask & 0x7;
|
||||
if buttons == 1 && evt_type == 1 && ctrl && self.peer_platform() != "Mac OS" {
|
||||
self.send_mouse((1 << 3 | 2) as _, x, y, alt, ctrl, shift, command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -820,20 +823,6 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
fn super_x(&mut self) {
|
||||
self.super_on = true;
|
||||
}
|
||||
|
||||
fn ctrl_space(&mut self) {
|
||||
let key = "VK_SPACE".to_owned();
|
||||
self.key_down_or_up(3, key, 0, false, true, false, false, false);
|
||||
}
|
||||
|
||||
fn alt_tab(&mut self) {
|
||||
let key = "VK_TAB".to_owned();
|
||||
self.key_down_or_up(3, key, 0, true, false, false, false, false);
|
||||
}
|
||||
|
||||
fn lock_screen(&mut self) {
|
||||
let lock = "LOCK_SCREEN".to_owned();
|
||||
self.key_down_or_up(1, lock, 0, false, false, false, false, false);
|
||||
@@ -866,6 +855,18 @@ impl Handler {
|
||||
command: bool,
|
||||
extended: bool,
|
||||
) {
|
||||
|
||||
if self.peer_platform() == "Windows" {
|
||||
if ctrl && alt && name == "VK_DELETE" {
|
||||
self.ctrl_alt_del();
|
||||
return;
|
||||
}
|
||||
if command && name == "VK_L" {
|
||||
self.lock_screen();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// extended: e.g. ctrl key on right side, https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-keybd_event
|
||||
// not found api of osx and xdo
|
||||
log::debug!(
|
||||
@@ -881,15 +882,6 @@ impl Handler {
|
||||
extended,
|
||||
);
|
||||
|
||||
let mut command = command;
|
||||
if self.super_on {
|
||||
command = true;
|
||||
}
|
||||
|
||||
if down_or_up == 0 {
|
||||
self.super_on = false;
|
||||
}
|
||||
|
||||
let mut name = name;
|
||||
#[cfg(target_os = "linux")]
|
||||
if code == 65383 {
|
||||
|
||||
Reference in New Issue
Block a user