[WebView] [TCSACR-219] Adds WebView.BackForwardList (#620)
[platform/core/csapi/tizenfx.git] / src / Tizen.WebView / Tizen.WebView / WebView.cs
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using ElmSharp;
18 using System;
19 using System.Collections.Generic;
20 using System.Runtime.InteropServices;
21
22 namespace Tizen.WebView
23 {
24     /// <summary>
25     /// A view used to render the web contents.
26     /// </summary>
27     /// <since_tizen> 4 </since_tizen>
28     public class WebView: EvasObject
29     {
30         private static IDictionary<string, JavaScriptMessageHandler> _javaScriptMessageHandlerMap = new Dictionary<string, JavaScriptMessageHandler>();
31
32         private IntPtr _handle;
33         private IntPtr _realHandle;
34         private Context _context;
35         private Settings _settings;
36
37         // focus dummy
38         private SmartEvent _focusIn;
39         private SmartEvent _focusOut;
40
41         // Smart events
42         private SmartEvent _loadStarted;
43         private SmartEvent _loadFinished;
44         private SmartEvent<SmartCallbackLoadErrorArgs> _loadError;
45         private SmartEvent<SmartCallbackArgs> _titleChanged;
46         private SmartEvent<SmartCallbackArgs> _urlChanged;
47
48
49
50         /// <summary>
51         /// Event that occurs when the load is started.
52         /// </summary>
53         /// <since_tizen> 4 </since_tizen>
54         public event EventHandler LoadStarted;
55
56         /// <summary>
57         /// Event that occurs when the load is finished.
58         /// </summary>
59         /// <since_tizen> 4 </since_tizen>
60         public event EventHandler LoadFinished;
61
62         /// <summary>
63         /// Event that occurs when the load throws an error.
64         /// </summary>
65         /// <since_tizen> 4 </since_tizen>
66         public event EventHandler<SmartCallbackLoadErrorArgs> LoadError;
67
68         /// <summary>
69         /// Event that occurs when the title of the main frame is changed.
70         /// </summary>
71         /// <since_tizen> 4 </since_tizen>
72         public event EventHandler<SmartCallbackArgs> TitleChanged;
73
74         /// <summary>
75         /// Event that occurs when the URL of the main frame is changed.
76         /// </summary>
77         /// <since_tizen> 4 </since_tizen>
78         public event EventHandler<SmartCallbackArgs> UrlChanged;
79
80         /// <summary>
81         /// Current URL of the main frame.
82         /// </summary>
83         /// <since_tizen> 4 </since_tizen>
84         public string Url
85         {
86             get
87             {
88                 return Interop.ChromiumEwk.ewk_view_url_get(_realHandle);
89             }
90         }
91
92         /// <summary>
93         /// Current title of the main frame.
94         /// </summary>
95         /// <since_tizen> 4 </since_tizen>
96         public string Title
97         {
98             get
99             {
100                 return Interop.ChromiumEwk.ewk_view_title_get(_realHandle);
101             }
102         }
103
104         /// <summary>
105         /// Current user agent string of this view.
106         /// </summary>
107         /// <since_tizen> 4 </since_tizen>
108         public string UserAgent
109         {
110             get
111             {
112                 return Interop.ChromiumEwk.ewk_view_user_agent_get(_realHandle);
113             }
114
115             set
116             {
117                 Interop.ChromiumEwk.ewk_view_user_agent_set(_realHandle, value);
118             }
119         }
120
121         /// <summary>
122         /// Whether a view has the focus.
123         /// </summary>
124         /// <since_tizen> 4 </since_tizen>
125         public bool HasFocus
126         {
127             get
128             {
129                 return Interop.ChromiumEwk.ewk_view_focus_get(_realHandle);
130             }
131         }
132
133         /// <summary>
134         /// Creates a WebView object.
135         /// </summary>
136         /// <param name="parent">Parent object of the WebView.</param>
137         /// <since_tizen> 4 </since_tizen>
138         public WebView(EvasObject parent) : base(parent)
139         {
140             InitializeSmartEvent();
141         }
142
143         /// <summary>
144         /// Gets the context object of this view.
145         /// </summary>
146         /// <returns>The context object of this view.</returns>
147         /// <since_tizen> 4 </since_tizen>
148         public Context GetContext()
149         {
150             if (_context == null)
151             {
152                 IntPtr contextHandle = Interop.ChromiumEwk.ewk_view_context_get(_realHandle);
153                 if (contextHandle == IntPtr.Zero)
154                 {
155                     return null;
156                 }
157                 _context = new Context(contextHandle);
158             }
159             return _context;
160         }
161
162         /// <summary>
163         /// Gets the settings object of this view.
164         /// </summary>
165         /// <returns>The settings object of this view.</returns>
166         /// <since_tizen> 4 </since_tizen>
167         public Settings GetSettings()
168         {
169             if (_settings == null)
170             {
171                 IntPtr settingsHandle = Interop.ChromiumEwk.ewk_view_settings_get(_realHandle);
172                 if (settingsHandle == IntPtr.Zero)
173                 {
174                     return null;
175                 }
176                 _settings = new Settings(settingsHandle);
177             }
178             return _settings;
179         }
180
181         /// <summary>
182         /// Gets the back/forward list object of this view.
183         /// </summary>
184         /// <returns>The BackForward List object of this view.</returns>
185         /// <since_tizen> 6 </since_tizen>
186         public BackForwardList GetBackForwardList()
187         {
188             IntPtr backforwardlistHandle = Interop.ChromiumEwk.ewk_view_back_forward_list_get(_realHandle);
189             if (backforwardlistHandle == IntPtr.Zero)
190             {
191                 return null;
192             }
193             return new BackForwardList(backforwardlistHandle);
194         }
195
196         /// <summary>
197         /// Clear the back/forward list object of this view.
198         /// </summary>
199         /// <since_tizen> 6 </since_tizen>
200         public void ClearBackForwardList()
201         {
202             Interop.ChromiumEwk.ewk_view_back_forward_list_clear(_realHandle);
203         }
204
205         /// <summary>
206         /// Asks the object to load the given URL.
207         /// </summary>
208         /// <remarks>
209         /// You can only be sure that the URL changes after UrlChanged event.
210         /// </remarks>
211         /// <param name="url">The uniform resource identifier to load.</param>
212         /// <since_tizen> 4 </since_tizen>
213         public void LoadUrl(string url)
214         {
215             Interop.ChromiumEwk.ewk_view_url_set(_realHandle, url);
216         }
217
218         /// <summary>
219         /// Loads the specified HTML string as the content of the view.
220         /// </summary>
221         /// <param name="html">HTML data to load.</param>
222         /// <param name="baseUrl">Base URL used for relative paths to external objects.</param>
223         /// <since_tizen> 4 </since_tizen>
224         public void LoadHtml(string html, string baseUrl)
225         {
226             Interop.ChromiumEwk.ewk_view_html_string_load(_realHandle, html, baseUrl, null);
227         }
228
229         /// <summary>
230         /// Asks the main frame to stop loading.
231         /// </summary>
232         /// <since_tizen> 4 </since_tizen>
233         public void StopLoading()
234         {
235             Interop.ChromiumEwk.ewk_view_stop(_realHandle);
236         }
237
238         /// <summary>
239         /// Asks the main frame to reload the current document.
240         /// </summary>
241         /// <since_tizen> 4 </since_tizen>
242         public void Reload()
243         {
244             Interop.ChromiumEwk.ewk_view_reload(_realHandle);
245         }
246
247         /// <summary>
248         /// Asks the main frame to navigate back in history.
249         /// </summary>
250         /// <since_tizen> 4 </since_tizen>
251         public void GoBack()
252         {
253             Interop.ChromiumEwk.ewk_view_back(_realHandle);
254         }
255
256         /// <summary>
257         /// Asks the main frame to navigate forward in history.
258         /// </summary>
259         /// <since_tizen> 4 </since_tizen>
260         public void GoForward()
261         {
262             Interop.ChromiumEwk.ewk_view_forward(_realHandle);
263         }
264
265         /// <summary>
266         /// Checks whether it is possible to navigate backward one item in history.
267         /// </summary>
268         /// <returns>Whether it is possible to navigate backward one item in history.</returns>
269         /// <since_tizen> 4 </since_tizen>
270         public bool CanGoBack()
271         {
272             return Interop.ChromiumEwk.ewk_view_back_possible(_realHandle);
273         }
274
275         /// <summary>
276         /// Checks whether it is possible to navigate forward one item in history.
277         /// </summary>
278         /// <returns>Whether it is possible to navigate forward one item in history.</returns>
279         /// <since_tizen> 4 </since_tizen>
280         public bool CanGoForward()
281         {
282             return Interop.ChromiumEwk.ewk_view_forward_possible(_realHandle);
283         }
284
285         /// <summary>
286         /// Injects the supplied javascript message handler into the view.
287         /// </summary>
288         /// <param name="name"> The message callback.</param>
289         /// <param name="handler">The name used to expose the object in JavaScript.</param>
290         /// <returns>'true' on success, otherwise 'false'.</returns>
291         /// <since_tizen> 4 </since_tizen>
292         public bool AddJavaScriptMessageHandler(string name, JavaScriptMessageHandler handler)
293         {
294             lock (_javaScriptMessageHandlerMap)
295             {
296                 if (_javaScriptMessageHandlerMap.ContainsKey(name))
297                 {
298                     return false;
299                 }
300                 _javaScriptMessageHandlerMap[name] = handler;
301             }
302             Interop.ChromiumEwk.ScriptMessageCallback callback = (handle, message) =>
303             {
304                 JavaScriptMessage convertedMessage = new JavaScriptMessage(message);
305                 lock (_javaScriptMessageHandlerMap)
306                 {
307                     if (_javaScriptMessageHandlerMap.ContainsKey(convertedMessage.Name))
308                     {
309                         _javaScriptMessageHandlerMap[convertedMessage.Name](convertedMessage);
310                     }
311                 }
312             };
313             if (!Interop.ChromiumEwk.ewk_view_javascript_message_handler_add(_realHandle, callback, name))
314             {
315                 lock (_javaScriptMessageHandlerMap)
316                 {
317                     _javaScriptMessageHandlerMap.Remove(name);
318                     return false;
319                 }
320             }
321             return true;
322         }
323
324         /// <summary>
325         /// Requests the execution of a given name and the result to the JavaScript runtime.
326         /// </summary>
327         /// <param name="name">The name used to expose the object in JavaScript.</param>
328         /// <param name="result">The result to the JavaScript runtime.</param>
329         /// <since_tizen> 4 </since_tizen>
330         public void EvalWithResult(string name, string result)
331         {
332             Interop.ChromiumEwk.ewk_view_evaluate_javascript(_realHandle, name, result);
333         }
334
335         /// <summary>
336         /// Requests the execution of the given script.
337         /// </summary>
338         /// <param name="script">The JavaScript code string to execute.</param>
339         /// <since_tizen> 4 </since_tizen>
340         public void Eval(string script)
341         {
342             Interop.ChromiumEwk.ewk_view_script_execute(_realHandle, script, null, IntPtr.Zero);
343         }
344
345         /// <summary>
346         /// Requests to set or unset a view as the currently focused one.
347         /// </summary>
348         /// <param name="focused">'true' to set the focus on the view, 'false' to remove the focus from the view.</param>
349         /// <since_tizen> 4 </since_tizen>
350         public void SetFocus(bool focused)
351         {
352             Interop.ChromiumEwk.ewk_view_focus_set(_realHandle, focused);
353         }
354
355         /// <summary>
356         /// Creates a widget handle.
357         /// </summary>
358         /// <param name="parent">Parent EvasObject.</param>
359         /// <returns>IntPtr of the widget handle.</returns>
360         /// <since_tizen> 4 </since_tizen>
361         protected override IntPtr CreateHandle(EvasObject parent)
362         {
363             // focus dummy
364             _handle = Interop.Elementary.elm_layout_add((IntPtr)parent);
365             Interop.Elementary.elm_layout_theme_set(_handle, "layout", "elm_widget", "default");
366             Interop.Elementary.elm_object_focus_allow_set(_handle, true);
367
368             IntPtr evas = Interop.Evas.evas_object_evas_get(parent);
369             _realHandle = Interop.ChromiumEwk.ewk_view_add(evas);
370             Interop.Elementary.elm_object_part_content_set(_handle, "elm.swallow.content", _realHandle);
371
372             return _handle;
373         }
374
375         private void InitializeSmartEvent()
376         {
377             // focus dummy
378             _focusIn = new SmartEvent(this, "focused");
379             _focusOut = new SmartEvent(this, "unfocused");
380
381             _focusIn.On += (s, e) => { ((WebView)s).SetFocus(true); };
382             _focusOut.On += (s, e) => { ((WebView)s).SetFocus(false); };
383
384             _loadStarted = new SmartEvent(this, _realHandle, "load,started");
385             _loadFinished = new SmartEvent(this, _realHandle, "load,finished");
386             _loadError = new SmartEvent<SmartCallbackLoadErrorArgs>(this, _realHandle, "load,error", SmartCallbackLoadErrorArgs.CreateFromSmartEvent);
387             _titleChanged = new SmartEvent<SmartCallbackArgs>(this, _realHandle, "title,changed", SmartCallbackArgs.CreateFromSmartEvent);
388             _urlChanged = new SmartEvent<SmartCallbackArgs>(this, _realHandle, "url,changed", SmartCallbackArgs.CreateFromSmartEvent);
389
390             _loadStarted.On += (s, e) => { LoadStarted?.Invoke(this, EventArgs.Empty); };
391             _loadFinished.On += (s, e) => { LoadFinished?.Invoke(this, EventArgs.Empty); };
392             _loadError.On += (s, e) => { LoadError?.Invoke(this, e); };
393             _titleChanged.On += (s, e) => { TitleChanged?.Invoke(this, e); };
394             _urlChanged.On += (s, e) => { UrlChanged?.Invoke(this, e); };
395         }
396     }
397 }