You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
7.0 KiB
206 lines
7.0 KiB
using Monaco.Helpers; |
|
using Newtonsoft.Json; |
|
using Newtonsoft.Json.Serialization; |
|
using System; |
|
using System.Linq; |
|
using System.Runtime.CompilerServices; |
|
using System.Runtime.Serialization; |
|
using System.Threading.Tasks; |
|
using Windows.Data.Json; |
|
using Windows.UI.Xaml.Controls; |
|
|
|
namespace Monaco.Extensions |
|
{ |
|
internal static class WebViewExtensions |
|
{ |
|
public static async Task RunScriptAsync( |
|
this WebView _view, |
|
string script, |
|
[CallerMemberName] string member = null, |
|
[CallerFilePath] string file = null, |
|
[CallerLineNumber] int line = 0) |
|
{ |
|
await _view.RunScriptAsync<object>(script, member, file, line); |
|
} |
|
|
|
public static async Task<T> RunScriptAsync<T>( |
|
this WebView _view, |
|
string script, |
|
[CallerMemberName] string member = null, |
|
[CallerFilePath] string file = null, |
|
[CallerLineNumber] int line = 0) |
|
{ |
|
var start = "try {\n"; |
|
if (typeof(T) != typeof(object)) |
|
{ |
|
script = script.Trim(';'); |
|
start += "JSON.stringify(" + script + ");"; |
|
} |
|
else |
|
{ |
|
start += script; |
|
} |
|
var fullscript = start + |
|
"\n} catch (err) { JSON.stringify({ wv_internal_error: true, message: err.message, description: err.description, number: err.number, stack: err.stack }); }"; |
|
|
|
if (_view.Dispatcher.HasThreadAccess) |
|
{ |
|
try |
|
{ |
|
return await RunScriptHelperAsync<T>(_view, fullscript); |
|
} |
|
catch (Exception e) |
|
{ |
|
throw new JavaScriptExecutionException(member, file, line, script, e); |
|
} |
|
} |
|
else |
|
{ |
|
return await _view.Dispatcher.RunTaskAsync(async () => |
|
{ |
|
try |
|
{ |
|
return await RunScriptHelperAsync<T>(_view, fullscript); |
|
} |
|
catch (Exception e) |
|
{ |
|
throw new JavaScriptExecutionException(member, file, line, script, e); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
private static async Task<T> RunScriptHelperAsync<T>(WebView _view, string script) |
|
{ |
|
var returnstring = await _view.InvokeScriptAsync("eval", new string[] { script }); |
|
|
|
if (JsonObject.TryParse(returnstring, out JsonObject result)) |
|
{ |
|
if (result.ContainsKey("wv_internal_error") && result["wv_internal_error"].ValueType == JsonValueType.Boolean && result["wv_internal_error"].GetBoolean()) |
|
{ |
|
throw new JavaScriptInnerException(result["message"].GetString(), result["stack"].GetString()); |
|
} |
|
} |
|
|
|
if (returnstring != null && returnstring != "null") |
|
{ |
|
return JsonConvert.DeserializeObject<T>(returnstring); |
|
} |
|
|
|
return default(T); |
|
} |
|
|
|
private static JsonSerializerSettings _settings = new JsonSerializerSettings() |
|
{ |
|
NullValueHandling = NullValueHandling.Ignore, |
|
ContractResolver = new CamelCasePropertyNamesContractResolver() |
|
}; |
|
|
|
public static async Task InvokeScriptAsync( |
|
this WebView _view, |
|
string method, |
|
object arg, |
|
bool serialize = true, |
|
[CallerMemberName] string member = null, |
|
[CallerFilePath] string file = null, |
|
[CallerLineNumber] int line = 0) |
|
{ |
|
await _view.InvokeScriptAsync<object>(method, arg, serialize, member, file, line); |
|
} |
|
|
|
public static async Task InvokeScriptAsync( |
|
this WebView _view, |
|
string method, |
|
object[] args, |
|
bool serialize = true, |
|
[CallerMemberName] string member = null, |
|
[CallerFilePath] string file = null, |
|
[CallerLineNumber] int line = 0) |
|
{ |
|
await _view.InvokeScriptAsync<object>(method, args, serialize, member, file, line); |
|
} |
|
|
|
public static async Task<T> InvokeScriptAsync<T>( |
|
this WebView _view, |
|
string method, |
|
object arg, |
|
bool serialize = true, |
|
[CallerMemberName] string member = null, |
|
[CallerFilePath] string file = null, |
|
[CallerLineNumber] int line = 0) |
|
{ |
|
return await _view.InvokeScriptAsync<T>(method, new object[] { arg }, serialize, member, file, line); |
|
} |
|
|
|
public static async Task<T> InvokeScriptAsync<T>( |
|
this WebView _view, |
|
string method, |
|
object[] args, |
|
bool serialize = true, |
|
[CallerMemberName] string member = null, |
|
[CallerFilePath] string file = null, |
|
[CallerLineNumber] int line = 0) |
|
{ |
|
string[] sanitizedargs; |
|
|
|
if (serialize) |
|
{ |
|
sanitizedargs = args.Select(item => |
|
{ |
|
if (item is int || item is double) |
|
{ |
|
return item.ToString(); |
|
} |
|
else if (item is string) |
|
{ |
|
return JsonConvert.ToString(item); |
|
} |
|
else |
|
{ |
|
// TODO: Need JSON.parse? |
|
return JsonConvert.SerializeObject(item, _settings); |
|
} |
|
}).ToArray(); |
|
} |
|
else |
|
{ |
|
sanitizedargs = args.Select(item => item.ToString()).ToArray(); |
|
} |
|
|
|
var script = method + "(" + string.Join(",", sanitizedargs) + ");"; |
|
|
|
return await RunScriptAsync<T>(_view, script, member, file, line); |
|
} |
|
} |
|
|
|
internal sealed class JavaScriptExecutionException : Exception |
|
{ |
|
public string Script { get; private set; } |
|
|
|
public string Member { get; private set; } |
|
|
|
public string FileName { get; private set; } |
|
|
|
public int LineNumber { get; private set; } |
|
|
|
public JavaScriptExecutionException(string member, string filename, int line, string script, Exception inner) |
|
: base("Error Executing JavaScript Code for " + member + "\nLine " + line + " of " + filename + "\n" + script + "\n", inner) |
|
{ |
|
this.Member = member; |
|
this.FileName = filename; |
|
this.LineNumber = line; |
|
this.Script = script; |
|
} |
|
} |
|
|
|
internal sealed class JavaScriptInnerException : Exception |
|
{ |
|
public string JavaScriptStackTrace { get; private set; } // TODO Use Enum of JS error types https://www.w3schools.com/js/js_errors.asp |
|
|
|
public JavaScriptInnerException(string message, string stack) |
|
: base(message) |
|
{ |
|
this.JavaScriptStackTrace = stack; |
|
} |
|
} |
|
}
|
|
|