mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-01 19:44:39 +03:00
feat(tauri) add dialog API (#514)
* feat(tauri) add dialog API * feat(example) add dialog API to the communication example * fix(dialog) transform backslash so it works on windows
This commit is contained in:
parent
b4a08e88fd
commit
37e8e79a04
32
cli/tauri.js/api/dialog.js
Normal file
32
cli/tauri.js/api/dialog.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import tauri from './tauri'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name openDialog
|
||||||
|
* @description Open a file/directory selection dialog
|
||||||
|
* @param {String} [options]
|
||||||
|
* @param {String} [options.filter]
|
||||||
|
* @param {String} [options.defaultPath]
|
||||||
|
* @param {Boolean} [options.multiple=false]
|
||||||
|
* @param {Boolean} [options.directory=false]
|
||||||
|
* @returns {Promise<String|String[]>} promise resolving to the select path(s)
|
||||||
|
*/
|
||||||
|
function open (options = {}) {
|
||||||
|
return tauri.openDialog(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name save
|
||||||
|
* @description Open a file/directory save dialog
|
||||||
|
* @param {String} [options]
|
||||||
|
* @param {String} [options.filter]
|
||||||
|
* @param {String} [options.defaultPath]
|
||||||
|
* @returns {Promise<String>} promise resolving to the select path
|
||||||
|
*/
|
||||||
|
function save (options = {}) {
|
||||||
|
return tauri.saveDialog(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
open,
|
||||||
|
save
|
||||||
|
}
|
@ -378,6 +378,66 @@ window.tauri = {
|
|||||||
<% } %>
|
<% } %>
|
||||||
},
|
},
|
||||||
|
|
||||||
|
<% if (ctx.dev) { %>
|
||||||
|
/**
|
||||||
|
* @name openDialog
|
||||||
|
* @description Open a file/directory selection dialog
|
||||||
|
* @param {String} [options]
|
||||||
|
* @param {String} [options.filter]
|
||||||
|
* @param {String} [options.defaultPath]
|
||||||
|
* @param {Boolean} [options.multiple=false]
|
||||||
|
* @param {Boolean} [options.directory=false]
|
||||||
|
* @returns {Promise<String|String[]>} promise resolving to the select path(s)
|
||||||
|
*/
|
||||||
|
<% } %>
|
||||||
|
openDialog: function openDialog(options) {
|
||||||
|
<% if (tauri.whitelist.openDialog === true || tauri.whitelist.all === true) { %>
|
||||||
|
var opts = options || {}
|
||||||
|
if (_typeof(options) === 'object') {
|
||||||
|
opts.default_path = opts.defaultPath
|
||||||
|
Object.freeze(options);
|
||||||
|
}
|
||||||
|
return this.promisified({
|
||||||
|
cmd: 'openDialog',
|
||||||
|
options: opts
|
||||||
|
});
|
||||||
|
<% } else { %>
|
||||||
|
<% if (ctx.dev) { %>
|
||||||
|
return __whitelistWarning('openDialog')
|
||||||
|
<% } %>
|
||||||
|
return __reject()
|
||||||
|
<% } %>
|
||||||
|
},
|
||||||
|
|
||||||
|
<% if (ctx.dev) { %>
|
||||||
|
/**
|
||||||
|
* @name saveDialog
|
||||||
|
* @description Open a file/directory save dialog
|
||||||
|
* @param {String} [options]
|
||||||
|
* @param {String} [options.filter]
|
||||||
|
* @param {String} [options.defaultPath]
|
||||||
|
* @returns {Promise<String>} promise resolving to the select path
|
||||||
|
*/
|
||||||
|
<% } %>
|
||||||
|
saveDialog: function saveDialog(options) {
|
||||||
|
<% if (tauri.whitelist.saveDialog === true || tauri.whitelist.all === true) { %>
|
||||||
|
var opts = options || {}
|
||||||
|
if (_typeof(options) === 'object') {
|
||||||
|
opts.default_path = opts.defaultPath
|
||||||
|
Object.freeze(options);
|
||||||
|
}
|
||||||
|
return this.promisified({
|
||||||
|
cmd: 'saveDialog',
|
||||||
|
options: opts
|
||||||
|
});
|
||||||
|
<% } else { %>
|
||||||
|
<% if (ctx.dev) { %>
|
||||||
|
return __whitelistWarning('saveDialog')
|
||||||
|
<% } %>
|
||||||
|
return __reject()
|
||||||
|
<% } %>
|
||||||
|
},
|
||||||
|
|
||||||
loadAsset: function loadAsset(assetName, assetType) {
|
loadAsset: function loadAsset(assetName, assetType) {
|
||||||
return this.promisified({
|
return this.promisified({
|
||||||
cmd: 'loadAsset',
|
cmd: 'loadAsset',
|
||||||
|
@ -22,6 +22,7 @@ tar = "0.4"
|
|||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
error-chain = "0.12"
|
error-chain = "0.12"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
|
nfd = "0.0.4"
|
||||||
tauri-utils = {version = "0.4", path = "../tauri-utils"}
|
tauri-utils = {version = "0.4", path = "../tauri-utils"}
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
33
tauri-api/src/dialog.rs
Normal file
33
tauri-api/src/dialog.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use nfd::{DialogType, open_dialog};
|
||||||
|
pub use nfd::Response;
|
||||||
|
|
||||||
|
fn open_dialog_internal(dialog_type: DialogType, filter: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
|
||||||
|
open_dialog(filter.as_deref(), default_path.as_deref(), dialog_type)
|
||||||
|
.map_err(|err| crate::Error::with_chain(err, "open dialog failed"))
|
||||||
|
.and_then(|response| {
|
||||||
|
match response {
|
||||||
|
Response::Cancel => Err(crate::Error::from("user cancelled")),
|
||||||
|
_ => Ok(response)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open single select file dialog
|
||||||
|
pub fn select(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
|
||||||
|
open_dialog_internal(DialogType::SingleFile, filter_list, default_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open mulitple select file dialog
|
||||||
|
pub fn select_multiple(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
|
||||||
|
open_dialog_internal(DialogType::MultipleFiles, filter_list, default_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open save dialog
|
||||||
|
pub fn save_file(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
|
||||||
|
open_dialog_internal(DialogType::SaveFile, filter_list, default_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open pick folder dialog
|
||||||
|
pub fn pick_folder(default_path: Option<String>) -> crate::Result<Response> {
|
||||||
|
open_dialog_internal(DialogType::PickFolder, None, default_path)
|
||||||
|
}
|
@ -9,6 +9,7 @@ pub mod file;
|
|||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
pub mod tcp;
|
pub mod tcp;
|
||||||
|
pub mod dialog;
|
||||||
|
|
||||||
pub use tauri_utils::*;
|
pub use tauri_utils::*;
|
||||||
|
|
||||||
|
@ -49,6 +49,8 @@ execute = []
|
|||||||
open = []
|
open = []
|
||||||
event = []
|
event = []
|
||||||
updater = []
|
updater = []
|
||||||
|
open-dialog = []
|
||||||
|
save-dialog = []
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["dev-server", "all-api"]
|
features = ["dev-server", "all-api"]
|
||||||
|
20
tauri/examples/communication/dist/dialog.js
vendored
Normal file
20
tauri/examples/communication/dist/dialog.js
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
var defaultPathInput = document.getElementById('dialog-default-path')
|
||||||
|
var filterInput = document.getElementById('dialog-filter')
|
||||||
|
var multipleInput = document.getElementById('dialog-multiple')
|
||||||
|
var directoryInput = document.getElementById('dialog-directory')
|
||||||
|
|
||||||
|
document.getElementById('open-dialog').addEventListener('click', function () {
|
||||||
|
window.tauri.openDialog({
|
||||||
|
defaultPath: defaultPathInput.value || null,
|
||||||
|
filter: filterInput.value || null,
|
||||||
|
multiple: multipleInput.checked,
|
||||||
|
directory: directoryInput.checked
|
||||||
|
}).then(registerResponse).catch(registerResponse)
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('save-dialog').addEventListener('click', function () {
|
||||||
|
window.tauri.saveDialog({
|
||||||
|
defaultPath: defaultPathInput.value || null,
|
||||||
|
filter: filterInput.value || null
|
||||||
|
}).then(registerResponse).catch(registerResponse)
|
||||||
|
})
|
17
tauri/examples/communication/dist/index.html
vendored
17
tauri/examples/communication/dist/index.html
vendored
@ -22,6 +22,22 @@
|
|||||||
<button id="set-title">Set title</button>
|
<button id="set-title">Set title</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 24px">
|
||||||
|
<input id="dialog-default-path" placeholder="Default path">
|
||||||
|
<input id="dialog-filter" placeholder="Extensions filter">
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" id="dialog-multiple">
|
||||||
|
<label>Multiple</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" id="dialog-directory">
|
||||||
|
<label>Directory</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="open-dialog">Open dialog</button>
|
||||||
|
<button id="save-dialog">Open save dialog</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="response"></div>
|
<div id="response"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -43,5 +59,6 @@
|
|||||||
<script src="communication.js"></script>
|
<script src="communication.js"></script>
|
||||||
<script src="fs.js"></script>
|
<script src="fs.js"></script>
|
||||||
<script src="window.js"></script>
|
<script src="window.js"></script>
|
||||||
|
<script src="dialog.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -333,6 +333,56 @@ window.tauri = {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name openDialog
|
||||||
|
* @description Open a file/directory selection dialog
|
||||||
|
* @param {String} [options]
|
||||||
|
* @param {String} [options.filter]
|
||||||
|
* @param {String} [options.defaultPath]
|
||||||
|
* @param {Boolean} [options.multiple=false]
|
||||||
|
* @param {Boolean} [options.directory=false]
|
||||||
|
* @returns {Promise<String|String[]>} promise resolving to the select path(s)
|
||||||
|
*/
|
||||||
|
|
||||||
|
openDialog: function openDialog(options) {
|
||||||
|
|
||||||
|
var opts = options || {}
|
||||||
|
if (_typeof(options) === 'object') {
|
||||||
|
opts.default_path = opts.defaultPath
|
||||||
|
Object.freeze(options);
|
||||||
|
}
|
||||||
|
return this.promisified({
|
||||||
|
cmd: 'openDialog',
|
||||||
|
options: opts
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name saveDialog
|
||||||
|
* @description Open a file/directory save dialog
|
||||||
|
* @param {String} [options]
|
||||||
|
* @param {String} [options.filter]
|
||||||
|
* @param {String} [options.defaultPath]
|
||||||
|
* @returns {Promise<String>} promise resolving to the select path
|
||||||
|
*/
|
||||||
|
|
||||||
|
saveDialog: function saveDialog(options) {
|
||||||
|
|
||||||
|
var opts = options || {}
|
||||||
|
if (_typeof(options) === 'object') {
|
||||||
|
opts.default_path = opts.defaultPath
|
||||||
|
Object.freeze(options);
|
||||||
|
}
|
||||||
|
return this.promisified({
|
||||||
|
cmd: 'saveDialog',
|
||||||
|
options: opts
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
loadAsset: function loadAsset(assetName, assetType) {
|
loadAsset: function loadAsset(assetName, assetType) {
|
||||||
return this.promisified({
|
return this.promisified({
|
||||||
cmd: 'loadAsset',
|
cmd: 'loadAsset',
|
||||||
@ -393,4 +443,4 @@ if (document.readyState === 'complete' || document.readyState === 'interactive')
|
|||||||
__openLinks()
|
__openLinks()
|
||||||
}, true)
|
}, true)
|
||||||
}
|
}
|
||||||
</script> <div> <button id="log">Call Log API</button> <button id="request">Call Request (async) API</button> <button id="event">Send event to Rust</button> </div> <div style="margin-top:24px"> <input id="path-to-read" placeholder="Type the path to read..."> <button id="read">Read</button> </div> <div style="margin-top:24px"> <input id="url" value="https://tauri.studio"> <button id="open-url">Open URL</button> </div> <div style="margin-top:24px"> <input id="title" value="Awesome Tauri Example!"> <button id="set-title">Set title</button> </div> <div id="response"></div> <script>function registerResponse(e){document.getElementById("response").innerHTML="object"==typeof e?JSON.stringify(e):e}function addClickEnterHandler(e,n,t){e.addEventListener("click",t),n.addEventListener("keyup",function(e){13===e.keyCode&&t()})}</script> <script>window.onTauriInit=function(){window.tauri.listen("rust-event",function(e){document.getElementById("response").innerHTML=JSON.stringify(e)})},document.getElementById("log").addEventListener("click",function(){window.tauri.invoke({cmd:"logOperation",event:"tauri-click",payload:"this payload is optional because we used Option in Rust"})}),document.getElementById("request").addEventListener("click",function(){window.tauri.promisified({cmd:"performRequest",endpoint:"dummy endpoint arg",body:{id:5,name:"test"}}).then(registerResponse).catch(registerResponse)}),document.getElementById("event").addEventListener("click",function(){window.tauri.emit("js-event","this is the payload string")});</script> <script>function arrayBufferToBase64(e,n){var t=new Blob([e],{type:"application/octet-binary"}),a=new FileReader;a.onload=function(e){var t=e.target.result;n(t.substr(t.indexOf(",")+1))},a.readAsDataURL(t)}var pathInput=document.getElementById("path-to-read");addClickEnterHandler(document.getElementById("read"),pathInput,function(){var a=pathInput.value,r=a.match(/\S+\.\S+$/g);(r?window.tauri.readBinaryFile(a):window.tauri.readDir(a)).then(function(e){if(r)if(a.includes(".png")||a.includes(".jpg"))arrayBufferToBase64(new Uint8Array(e),function(e){registerResponse('<img src="'+("data:image/png;base64,"+e)+'"></img>')});else{var t=String.fromCharCode.apply(null,e);registerResponse('<textarea id="file-response" style="height: 400px"></textarea><button id="file-save">Save</button>');var n=document.getElementById("file-response");n.value=t,document.getElementById("file-save").addEventListener("click",function(){window.tauri.writeFile({file:a,contents:n.value}).catch(registerResponse)})}else registerResponse(e)}).catch(registerResponse)});</script> <script>var urlInput=document.getElementById("url");addClickEnterHandler(document.getElementById("open-url"),urlInput,function(){window.tauri.open(urlInput.value)});var titleInput=document.getElementById("title");addClickEnterHandler(document.getElementById("set-title"),titleInput,function(){window.tauri.setTitle(titleInput.value)});</script> </body></html>
|
</script> <div> <button id="log">Call Log API</button> <button id="request">Call Request (async) API</button> <button id="event">Send event to Rust</button> </div> <div style="margin-top:24px"> <input id="path-to-read" placeholder="Type the path to read..."> <button id="read">Read</button> </div> <div style="margin-top:24px"> <input id="url" value="https://tauri.studio"> <button id="open-url">Open URL</button> </div> <div style="margin-top:24px"> <input id="title" value="Awesome Tauri Example!"> <button id="set-title">Set title</button> </div> <div style="margin-top:24px"> <input id="dialog-default-path" placeholder="Default path"> <input id="dialog-filter" placeholder="Extensions filter"> <div> <input type="checkbox" id="dialog-multiple"> <label>Multiple</label> </div> <div> <input type="checkbox" id="dialog-directory"> <label>Directory</label> </div> <button id="open-dialog">Open dialog</button> <button id="save-dialog">Open save dialog</button> </div> <div id="response"></div> <script>function registerResponse(e){document.getElementById("response").innerHTML="object"==typeof e?JSON.stringify(e):e}function addClickEnterHandler(e,n,t){e.addEventListener("click",t),n.addEventListener("keyup",function(e){13===e.keyCode&&t()})}</script> <script>window.onTauriInit=function(){window.tauri.listen("rust-event",function(e){document.getElementById("response").innerHTML=JSON.stringify(e)})},document.getElementById("log").addEventListener("click",function(){window.tauri.invoke({cmd:"logOperation",event:"tauri-click",payload:"this payload is optional because we used Option in Rust"})}),document.getElementById("request").addEventListener("click",function(){window.tauri.promisified({cmd:"performRequest",endpoint:"dummy endpoint arg",body:{id:5,name:"test"}}).then(registerResponse).catch(registerResponse)}),document.getElementById("event").addEventListener("click",function(){window.tauri.emit("js-event","this is the payload string")});</script> <script>function arrayBufferToBase64(e,n){var t=new Blob([e],{type:"application/octet-binary"}),a=new FileReader;a.onload=function(e){var t=e.target.result;n(t.substr(t.indexOf(",")+1))},a.readAsDataURL(t)}var pathInput=document.getElementById("path-to-read");addClickEnterHandler(document.getElementById("read"),pathInput,function(){var a=pathInput.value,r=a.match(/\S+\.\S+$/g);(r?window.tauri.readBinaryFile(a):window.tauri.readDir(a)).then(function(e){if(r)if(a.includes(".png")||a.includes(".jpg"))arrayBufferToBase64(new Uint8Array(e),function(e){registerResponse('<img src="'+("data:image/png;base64,"+e)+'"></img>')});else{var t=String.fromCharCode.apply(null,e);registerResponse('<textarea id="file-response" style="height: 400px"></textarea><button id="file-save">Save</button>');var n=document.getElementById("file-response");n.value=t,document.getElementById("file-save").addEventListener("click",function(){window.tauri.writeFile({file:a,contents:n.value}).catch(registerResponse)})}else registerResponse(e)}).catch(registerResponse)});</script> <script>var urlInput=document.getElementById("url");addClickEnterHandler(document.getElementById("open-url"),urlInput,function(){window.tauri.open(urlInput.value)});var titleInput=document.getElementById("title");addClickEnterHandler(document.getElementById("set-title"),titleInput,function(){window.tauri.setTitle(titleInput.value)});</script> <script>var defaultPathInput=document.getElementById("dialog-default-path"),filterInput=document.getElementById("dialog-filter"),multipleInput=document.getElementById("dialog-multiple"),directoryInput=document.getElementById("dialog-directory");document.getElementById("open-dialog").addEventListener("click",function(){window.tauri.openDialog({defaultPath:defaultPathInput.value||null,filter:filterInput.value||null,multiple:multipleInput.checked,directory:directoryInput.checked}).then(registerResponse).catch(registerResponse)}),document.getElementById("save-dialog").addEventListener("click",function(){window.tauri.saveDialog({defaultPath:defaultPathInput.value||null,filter:filterInput.value||null}).then(registerResponse).catch(registerResponse)});</script> </body></html>
|
@ -2,6 +2,7 @@ mod cmd;
|
|||||||
mod salt;
|
mod salt;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod file_system;
|
mod file_system;
|
||||||
|
mod dialog;
|
||||||
|
|
||||||
#[cfg(not(any(feature = "dev-server", feature = "embedded-server")))]
|
#[cfg(not(any(feature = "dev-server", feature = "embedded-server")))]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -94,6 +95,22 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
|
|||||||
Emit { event, payload } => {
|
Emit { event, payload } => {
|
||||||
crate::event::on_event(event, payload);
|
crate::event::on_event(event, payload);
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "all-api", feature = "open-dialog"))]
|
||||||
|
OpenDialog {
|
||||||
|
options,
|
||||||
|
callback,
|
||||||
|
error
|
||||||
|
} => {
|
||||||
|
dialog::open(webview, options, callback, error);
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "all-api", feature = "save-dialog"))]
|
||||||
|
SaveDialog {
|
||||||
|
options,
|
||||||
|
callback,
|
||||||
|
error,
|
||||||
|
} => {
|
||||||
|
dialog::save(webview, options, callback, error);
|
||||||
|
}
|
||||||
#[cfg(not(any(feature = "dev-server", feature = "embedded-server")))]
|
#[cfg(not(any(feature = "dev-server", feature = "embedded-server")))]
|
||||||
LoadAsset {
|
LoadAsset {
|
||||||
asset,
|
asset,
|
||||||
|
@ -6,6 +6,22 @@ pub struct ReadDirOptions {
|
|||||||
pub recursive: bool
|
pub recursive: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct OpenDialogOptions {
|
||||||
|
pub filter: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub multiple: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub directory: bool,
|
||||||
|
pub default_path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct SaveDialogOptions {
|
||||||
|
pub filter: Option<String>,
|
||||||
|
pub default_path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(tag = "cmd", rename_all = "camelCase")]
|
#[serde(tag = "cmd", rename_all = "camelCase")]
|
||||||
pub enum Cmd {
|
pub enum Cmd {
|
||||||
@ -67,6 +83,18 @@ pub enum Cmd {
|
|||||||
event: String,
|
event: String,
|
||||||
payload: Option<String>,
|
payload: Option<String>,
|
||||||
},
|
},
|
||||||
|
#[cfg(any(feature = "all-api", feature = "open-dialog"))]
|
||||||
|
OpenDialog {
|
||||||
|
options: OpenDialogOptions,
|
||||||
|
callback: String,
|
||||||
|
error: String,
|
||||||
|
},
|
||||||
|
#[cfg(any(feature = "all-api", feature = "save-dialog"))]
|
||||||
|
SaveDialog {
|
||||||
|
options: SaveDialogOptions,
|
||||||
|
callback: String,
|
||||||
|
error: String,
|
||||||
|
},
|
||||||
#[cfg(not(any(feature = "dev-server", feature = "embedded-server")))]
|
#[cfg(not(any(feature = "dev-server", feature = "embedded-server")))]
|
||||||
LoadAsset {
|
LoadAsset {
|
||||||
asset: String,
|
asset: String,
|
||||||
|
54
tauri/src/endpoints/dialog.rs
Normal file
54
tauri/src/endpoints/dialog.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use crate::api::dialog::{select, select_multiple, save_file, pick_folder, Response};
|
||||||
|
use super::cmd::{OpenDialogOptions, SaveDialogOptions};
|
||||||
|
use web_view::WebView;
|
||||||
|
|
||||||
|
fn map_response(response: Response) -> String {
|
||||||
|
match response {
|
||||||
|
Response::Okay(path) => format!(r#""{}""#, path).replace("\\", "\\\\"),
|
||||||
|
Response::OkayMultiple(paths) => format!("{:?}", paths),
|
||||||
|
Response::Cancel => panic!("unexpected response type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open<T: 'static>(
|
||||||
|
webview: &mut WebView<'_, T>,
|
||||||
|
options: OpenDialogOptions,
|
||||||
|
callback: String,
|
||||||
|
error: String,
|
||||||
|
) {
|
||||||
|
crate::execute_promise_sync(
|
||||||
|
webview,
|
||||||
|
move || {
|
||||||
|
let response = if options.multiple {
|
||||||
|
select_multiple(options.filter, options.default_path)
|
||||||
|
} else if options.directory {
|
||||||
|
pick_folder(options.default_path)
|
||||||
|
} else {
|
||||||
|
select(options.filter, options.default_path)
|
||||||
|
};
|
||||||
|
response
|
||||||
|
.map(|r| map_response(r))
|
||||||
|
.map_err(|e| crate::ErrorKind::Dialog(e.to_string()).into())
|
||||||
|
},
|
||||||
|
callback,
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save<T: 'static>(
|
||||||
|
webview: &mut WebView<'_, T>,
|
||||||
|
options: SaveDialogOptions,
|
||||||
|
callback: String,
|
||||||
|
error: String,
|
||||||
|
) {
|
||||||
|
crate::execute_promise_sync(
|
||||||
|
webview,
|
||||||
|
move || {
|
||||||
|
save_file(options.filter, options.default_path)
|
||||||
|
.map(|r| map_response(r))
|
||||||
|
.map_err(|e| crate::ErrorKind::Dialog(e.to_string()).into())
|
||||||
|
},
|
||||||
|
callback,
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
}
|
@ -42,6 +42,10 @@ error_chain! {
|
|||||||
description("Command Error")
|
description("Command Error")
|
||||||
display("Command Error: '{}'", t)
|
display("Command Error: '{}'", t)
|
||||||
}
|
}
|
||||||
|
Dialog(t: String) {
|
||||||
|
description("Dialog Error")
|
||||||
|
display("Dialog Error: '{}'", t)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +59,20 @@ pub fn spawn<F: FnOnce() -> () + Send + 'static>(task: F) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn execute_promise_sync<T: 'static, F: FnOnce() -> crate::Result<String> + Send + 'static>(
|
||||||
|
webview: &mut WebView<'_, T>,
|
||||||
|
task: F,
|
||||||
|
callback: String,
|
||||||
|
error: String,
|
||||||
|
) {
|
||||||
|
let handle = webview.handle();
|
||||||
|
let callback_string =
|
||||||
|
api::rpc::format_callback_result(task().map_err(|err| err.to_string()), callback, error);
|
||||||
|
handle
|
||||||
|
.dispatch(move |_webview| _webview.eval(callback_string.as_str()))
|
||||||
|
.expect("Failed to dispatch promise callback");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn execute_promise<T: 'static, F: FnOnce() -> crate::Result<String> + Send + 'static>(
|
pub fn execute_promise<T: 'static, F: FnOnce() -> crate::Result<String> + Send + 'static>(
|
||||||
webview: &mut WebView<'_, T>,
|
webview: &mut WebView<'_, T>,
|
||||||
task: F,
|
task: F,
|
||||||
|
Loading…
Reference in New Issue
Block a user