/* * 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); }; } } }