/*
* Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using ElmSharp;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Tizen.WebView
{
///
/// A view used to render web contents.
///
public class WebView: EvasObject
{
private static IDictionary _javaScriptMessageHandlerMap = new Dictionary();
private IntPtr _handle;
private IntPtr _realHandle;
private Context _context;
private Settings _settings;
// focus dummy
private SmartEvent _focusIn;
private SmartEvent _focusOut;
// Smart events
private SmartEvent _loadStarted;
private SmartEvent _loadFinished;
private SmartEvent _loadError;
private SmartEvent _titleChanged;
private SmartEvent _urlChanged;
///
/// Event that occurs when load started.
///
public event EventHandler LoadStarted;
///
/// Event that occurs when load finished.
///
public event EventHandler LoadFinished;
///
/// Event that occurs when load error.
///
public event EventHandler LoadError;
///
/// Event that occurs when title of main frame was changed.
///
public event EventHandler TitleChanged;
///
/// Event that occurs when URL of main frame was changed.
///
public event EventHandler UrlChanged;
///
/// Current URL of the main frame.
///
public string Url
{
get
{
return Interop.ChromiumEwk.ewk_view_url_get(_realHandle);
}
}
///
/// Current title of the main frame.
///
public string Title
{
get
{
return Interop.ChromiumEwk.ewk_view_title_get(_realHandle);
}
}
///
/// Current user agent string of this view.
///
public string UserAgent
{
get
{
return Interop.ChromiumEwk.ewk_view_user_agent_get(_realHandle);
}
set
{
Interop.ChromiumEwk.ewk_view_user_agent_set(_realHandle, value);
}
}
///
/// Whether a view has the focus.
///
public bool HasFocus
{
get
{
return Interop.ChromiumEwk.ewk_view_focus_get(_realHandle);
}
}
///
/// Create a WebView object.
///
/// Parent object of WebView
public WebView(EvasObject parent) : base(parent)
{
InitializeSmartEvent();
}
///
/// Gets the Context object of this view.
///
/// The Context object of this view
public Context GetContext()
{
if (_context == null)
{
IntPtr contextHandle = Interop.ChromiumEwk.ewk_view_context_get(_realHandle);
if (contextHandle == IntPtr.Zero)
{
return null;
}
_context = new Context(contextHandle);
}
return _context;
}
///
/// Gets the Settings object of this view.
///
/// The Settings object of this view
public Settings GetSettings()
{
if (_settings == null)
{
IntPtr settingsHandle = Interop.ChromiumEwk.ewk_view_settings_get(_realHandle);
if (settingsHandle == IntPtr.Zero)
{
return null;
}
_settings = new Settings(settingsHandle);
}
return _settings;
}
///
/// Asks the object to load the given URL.
///
///
/// You can only be sure that url changed after UrlChanged event.
///
/// The uniform resource identifier to load
public void LoadUrl(string url)
{
Interop.ChromiumEwk.ewk_view_url_set(_realHandle, url);
}
///
/// Loads the specified html string as the content of the view.
///
/// HTML data to load
/// Base URL used for relative paths to external objects
public void LoadHtml(string html, string baseUrl)
{
Interop.ChromiumEwk.ewk_view_html_string_load(_realHandle, html, baseUrl, null);
}
///
/// Asks the main frame to stop loading.
///
public void StopLoading()
{
Interop.ChromiumEwk.ewk_view_stop(_realHandle);
}
///
/// Asks the main frame to reload the current document.
///
public void Reload()
{
Interop.ChromiumEwk.ewk_view_reload(_realHandle);
}
///
/// Asks the main frame to navigate back in history.
///
public void GoBack()
{
Interop.ChromiumEwk.ewk_view_back(_realHandle);
}
///
/// Asks the main frame to navigate forward in history.
///
public void GoForward()
{
Interop.ChromiumEwk.ewk_view_forward(_realHandle);
}
///
/// Checks whether it is possible to navigate backwards one item in history.
///
/// Whether it is possible to navigate backwards one item in history
public bool CanGoBack()
{
return Interop.ChromiumEwk.ewk_view_back_possible(_realHandle);
}
///
/// Checks whether it is possible to navigate forwards one item in history.
///
/// Whether it is possible to navigate forwards one item in history
public bool CanGoForward()
{
return Interop.ChromiumEwk.ewk_view_forward_possible(_realHandle);
}
///
/// Injects the supplied javascript message handler into the view.
///
/// The message callback
/// The name used to expose the object in JavaScript
/// 'true' on success, otherwise 'false'
public bool AddJavaScriptMessageHandler(string name, JavaScriptMessageHandler handler)
{
lock (_javaScriptMessageHandlerMap)
{
if (_javaScriptMessageHandlerMap.ContainsKey(name))
{
return false;
}
_javaScriptMessageHandlerMap[name] = handler;
}
Interop.ChromiumEwk.ScriptMessageCallback callback = (handle, message) =>
{
JavaScriptMessage convertedMessage = new JavaScriptMessage(message);
lock (_javaScriptMessageHandlerMap)
{
if (_javaScriptMessageHandlerMap.ContainsKey(convertedMessage.Name))
{
_javaScriptMessageHandlerMap[convertedMessage.Name](convertedMessage);
}
}
};
if (!Interop.ChromiumEwk.ewk_view_javascript_message_handler_add(_realHandle, callback, name))
{
lock (_javaScriptMessageHandlerMap)
{
_javaScriptMessageHandlerMap.Remove(name);
return false;
}
}
return true;
}
///
/// Requests the execution of given name and result to the JavaScript runtime.
///
/// The name used to expose the object in JavaScript
/// The result to the JavaScript runtime
public void EvalWithResult(string name, string result)
{
Interop.ChromiumEwk.ewk_view_evaluate_javascript(_realHandle, name, result);
}
///
/// Requests the execution of the given script.
///
/// The JavaScript code string to execute
public void Eval(string script)
{
Interop.ChromiumEwk.ewk_view_script_execute(_realHandle, script, null, IntPtr.Zero);
}
///
/// Requests to set or unset a view as the currently focused one.
///
/// 'true' to set the focus on the view, 'false' to remove the focus from the view
public void SetFocus(bool focused)
{
Interop.ChromiumEwk.ewk_view_focus_set(_realHandle, focused);
}
protected override IntPtr CreateHandle(EvasObject parent)
{
// focus dummy
_handle = Interop.Elementary.elm_layout_add((IntPtr)parent);
Interop.Elementary.elm_layout_theme_set(_handle, "layout", "elm_widget", "default");
Interop.Elementary.elm_object_focus_allow_set(_handle, true);
IntPtr evas = Interop.Evas.evas_object_evas_get(parent);
_realHandle = Interop.ChromiumEwk.ewk_view_add(evas);
Interop.Elementary.elm_object_part_content_set(_handle, "elm.swallow.content", _realHandle);
return _handle;
}
private void InitializeSmartEvent()
{
// focus dummy
_focusIn = new SmartEvent(this, "focused");
_focusOut = new SmartEvent(this, "unfocused");
_focusIn.On += (s, e) => { ((WebView)s).SetFocus(true); };
_focusOut.On += (s, e) => { ((WebView)s).SetFocus(false); };
_loadStarted = new SmartEvent(this, _realHandle, "load,started");
_loadFinished = new SmartEvent(this, _realHandle, "load,finished");
_loadError = new SmartEvent(this, _realHandle, "load,error", SmartCallbackLoadErrorArgs.CreateFromSmartEvent);
_titleChanged = new SmartEvent(this, _realHandle, "title,changed", SmartCallbackArgs.CreateFromSmartEvent);
_urlChanged = new SmartEvent(this, _realHandle, "url,changed", SmartCallbackArgs.CreateFromSmartEvent);
_loadStarted.On += (s, e) => { LoadStarted?.Invoke(this, EventArgs.Empty); };
_loadFinished.On += (s, e) => { LoadFinished?.Invoke(this, EventArgs.Empty); };
_loadError.On += (s, e) => { LoadError?.Invoke(this, e); };
_titleChanged.On += (s, e) => { TitleChanged?.Invoke(this, e); };
_urlChanged.On += (s, e) => { UrlChanged?.Invoke(this, e); };
}
}
}