/// <summary> /// /// </summary> /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param> /// <param name="src">the source of the element to load the stylesheet by</param> /// <param name="attributes">the attributes of the link element</param> public static string LoadStylesheet(HtmlContainer htmlContainer, string src, Dictionary <string, string> attributes) { ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer"); try { var args = new HtmlStylesheetLoadEventArgs(src, attributes); htmlContainer.RaiseHtmlStylesheetLoadEvent(args); if (args.SetStyleSheet != null) { return(args.SetStyleSheet); } else if (args.SetSrc != null) { return(LoadStylesheet(htmlContainer, args.SetSrc)); } else { return(LoadStylesheet(htmlContainer, src)); } } catch (Exception ex) { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Exception in handling stylesheet source", ex); return(string.Empty); } }
/// <summary> /// Load Vimeo video data (title, image, link) by calling Vimeo API. /// </summary> private void LoadVimeoDataAsync(Uri uri) { ThreadPool.QueueUserWorkItem(state => { try { var apiUri = new Uri(string.Format( "http://vimeo.com/api/v2/video/{0}.json", uri.Segments[2])); var client = new WebClient(); client.Encoding = Encoding.UTF8; client.DownloadStringCompleted += OnDownloadVimeoApiCompleted; client.DownloadStringAsync(apiUri); } catch (Exception ex) { _imageLoadingComplete = true; SetErrorBorder(); HtmlContainer.ReportError(HtmlRenderErrorType.Iframe, "Failed to get vimeo video data: " + uri, ex); HtmlContainer.RequestRefresh(false); } }); }
/// <summary> /// /// </summary> /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param> /// <param name="src">the source of the element to load the stylesheet by</param> /// <param name="attributes">the attributes of the link element</param> public static string LoadStylesheet(HtmlContainer htmlContainer, string src, Dictionary<string, string> attributes) { ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer"); try { var args = new HtmlStylesheetLoadEventArgs(src, attributes); htmlContainer.RaiseHtmlStylesheetLoadEvent(args); if(args.SetStyleSheet != null) { return args.SetStyleSheet; } else if(args.SetSrc != null) { return LoadStylesheet(htmlContainer, args.SetSrc); } else { return LoadStylesheet(htmlContainer, src); } } catch (Exception ex) { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Exception in handling stylesheet source", ex); return string.Empty; } }
/// <summary> /// Load YouTube video data (title, image, link) by calling YouTube API. /// </summary> private void LoadYoutubeDataAsync(Uri uri) { ThreadPool.QueueUserWorkItem(state => { try { var apiUri = new Uri( string.Format( "http://gdata.youtube.com/feeds/api/videos/{0}?v=2&alt=json", uri.Segments[2])); var client = new WebClient(); client.Encoding = Encoding.UTF8; client.DownloadStringCompleted += OnDownloadYoutubeApiCompleted; client.DownloadStringAsync(apiUri); } catch (Exception ex) { HtmlContainer.ReportError(HtmlRenderErrorType.Iframe, "Failed to get youtube video data: " + uri, ex); HtmlContainer.RequestRefresh(false); } }); }
/// <summary> /// Load stylesheet data from the given source.<br/> /// The source can be local file or web URI.<br/> /// First raise <see cref="HtmlStylesheetLoadEventArgs"/> event to allow the client to overwrite the stylesheet loading.<br/> /// If the stylesheet is downloaded from URI we will try to correct local URIs to absolute.<br/> /// </summary> /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param> /// <param name="src">the source of the element to load the stylesheet by</param> /// <param name="attributes">the attributes of the link element</param> /// <param name="stylesheet">return the stylesheet string that has been loaded (null if failed or <paramref name="stylesheetData"/> is given)</param> /// <param name="stylesheetData">return stylesheet data object that was provided by overwrite (null if failed or <paramref name="stylesheet"/> is given)</param> public static void LoadStylesheet(HtmlContainer htmlContainer, string src, Dictionary <string, string> attributes, out string stylesheet, out CssData stylesheetData) { ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer"); stylesheet = null; stylesheetData = null; try { var args = new HtmlStylesheetLoadEventArgs(src, attributes); htmlContainer.RaiseHtmlStylesheetLoadEvent(args); if (!string.IsNullOrEmpty(args.SetStyleSheet)) { stylesheet = args.SetStyleSheet; } else if (args.SetStyleSheetData != null) { stylesheetData = args.SetStyleSheetData; } else if (args.SetSrc != null) { stylesheet = LoadStylesheet(htmlContainer, args.SetSrc); } else { stylesheet = LoadStylesheet(htmlContainer, src); } } catch (Exception ex) { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Exception in handling stylesheet source", ex); } }
/// <summary> /// Set image of this image box by analyzing the src attribute.<br/> /// Load the image from inline base64 encoded string.<br/> /// Or from calling property/method on the bridge object that returns image or url to image.<br/> /// Or from file path<br/> /// Or from URI. /// </summary> /// <remarks> /// File path and URI image loading is executed async and after finishing calling <see cref="ImageLoadComplete"/> /// on the main thread and not threadpool. /// </remarks> /// <param name="htmlContainer">the container of the html to handle load image for</param> /// <param name="src">the source of the image to load</param> /// <param name="attributes">the collection of attributes on the element to use in event</param> /// <returns>the image object (null if failed)</returns> public void LoadImage(HtmlContainer htmlContainer, string src, Dictionary <string, string> attributes) { ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer"); _htmlContainer = htmlContainer; try { var args = new HtmlImageLoadEventArgs(src, attributes, OnHtmlImageLoadEventCallback); _htmlContainer.RaiseHtmlImageLoadEvent(args); if (!args.Handled) { if (!string.IsNullOrEmpty(src)) { if (src.StartsWith("data:image", StringComparison.CurrentCultureIgnoreCase)) { _image = GetImageFromData(src); if (_image == null) { _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Failed extract image from inline data"); } _releaseImageObject = true; ImageLoadComplete(false); } else { SetImageFromPath(src); } } else { ImageLoadComplete(false); } } } catch (Exception ex) { _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Exception in handling image source", ex); ImageLoadComplete(false); } }
/// <summary> /// Set image of this image box by analyzing the src attribute.<br/> /// Load the image from inline base64 encoded string.<br/> /// Or from calling property/method on the bridge object that returns image or URL to image.<br/> /// Or from file path<br/> /// Or from URI. /// </summary> /// <remarks> /// File path and URI image loading is executed async and after finishing calling <see cref="ImageLoadComplete"/> /// on the main thread and not thread-pool. /// </remarks> /// <param name="src">the source of the image to load</param> /// <param name="attributes">the collection of attributes on the element to use in event</param> /// <returns>the image object (null if failed)</returns> public void LoadImage(string src, Dictionary <string, string> attributes) { try { var args = new HtmlImageLoadEventArgs(src, attributes, OnHtmlImageLoadEventCallback); _htmlContainer.RaiseHtmlImageLoadEvent(args); _asyncCallback = !_htmlContainer.AvoidAsyncImagesLoading; if (!args.Handled) { if (!string.IsNullOrEmpty(src)) { if (src.StartsWith("data:image", StringComparison.CurrentCultureIgnoreCase)) { SetFromInlineData(src); } else { SetImageFromPath(src); } } else { ImageLoadComplete(false); } } } catch (Exception ex) { _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Exception in handling image source", ex); ImageLoadComplete(false); } }
/// <summary> /// Handle error occurred during video data load to handle if the video was not found. /// </summary> /// <param name="ex">the exception that occurred during data load web request</param> /// <param name="source">the name of the video source (YouTube/Vimeo/Etc.)</param> private void HandleDataLoadFailure(Exception ex, string source) { var webResponse = ex is WebException webError ? webError.Response as HttpWebResponse : null; if (webResponse != null && webResponse.StatusCode == HttpStatusCode.NotFound) { _videoTitle = "The video is not found, possibly removed by the user."; } else { HtmlContainer.ReportError(HtmlRenderErrorType.Iframe, "Failed to load " + source + " video data", ex); } }
/// <summary> /// Load the stylesheet from local file by given path. /// </summary> /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param> /// <param name="path">the stylesheet file to load</param> /// <returns>the loaded stylesheet string</returns> private static string LoadStylesheetFromFile(HtmlContainer htmlContainer, string path) { var fileInfo = CommonUtils.TryGetFileInfo(path); if (fileInfo != null) { if (fileInfo.Exists) { using (var sr = new StreamReader(fileInfo.FullName)) { return(sr.ReadToEnd()); } } else { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "No stylesheet found by path: " + path); } } else { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Failed load image, invalid source: " + path); } return(string.Empty); }
/// <summary> /// Load the image from inline base64 encoded string data. /// </summary> /// <param name="src">the source that has the base64 encoded image</param> private void SetFromInlineData(string src) { _image = GetImageFromData(src); if (_image == null) { _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Failed extract image from inline data"); } _releaseImageObject = true; ImageLoadComplete(false); }
/// <summary> /// Load the stylesheet from uri by downloading the string. /// </summary> /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param> /// <param name="uri">the uri to download from</param> /// <returns>the loaded stylesheet string</returns> private static string LoadStylesheetFromUri(HtmlContainer htmlContainer, Uri uri) { using (var client = new WebClient()) { var stylesheet = client.DownloadString(uri); try { stylesheet = CorrectRelativeUrls(stylesheet, uri); } catch (Exception ex) { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Error in correcting relative URL in loaded stylesheet", ex); } return(stylesheet); } }
/// <summary> /// Handle link click. /// </summary> private void OnOpenLinkClick(object sender, EventArgs eventArgs) { try { Point mp = _parentControl.PointToClient(Control.MousePosition); _currentLink.HtmlContainer.HandleLinkClicked(_parentControl, new MouseEventArgs(MouseButtons.None, 0, mp.X, mp.Y, 0), _currentLink); } catch (HtmlLinkClickedException) { throw; } catch (Exception ex) { _htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to open link", ex); } finally { DisposeContextMenu(); } }
/// <summary> /// Load image from path of image file or uri. /// </summary> /// <param name="path">the file path or uri to load image from</param> public void SetImageFromPath(string path) { var uri = CommonUtils.TryGetUri(path); if (uri != null && uri.Scheme != "file") { SetImageFromUri(uri); } else { var fileInfo = CommonUtils.TryGetFileInfo(uri != null ? uri.AbsolutePath : path); if (fileInfo != null) { SetImageFromFile(fileInfo); } else { _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Failed load image, invalid source: " + path); ImageLoadComplete(false); } } }
/// <summary> /// Parse Vimeo API response to get video data (title, image, link). /// </summary> private void OnDownloadVimeoApiCompleted(object sender, DownloadStringCompletedEventArgs e) { try { if (!e.Cancelled) { if (e.Error == null) { var idx = e.Result.IndexOf("\"title\"", StringComparison.Ordinal); if (idx > -1) { idx = e.Result.IndexOf('"', idx + 7); if (idx > -1) { var endIdx = e.Result.IndexOf('"', idx + 1); while (e.Result[endIdx - 1] == '\\') { endIdx = e.Result.IndexOf('"', endIdx + 1); } if (endIdx > -1) { _videoTitle = e.Result.Substring(idx + 1, endIdx - idx - 1).Replace("\\\"", "\""); } } } idx = e.Result.IndexOf("\"thumbnail_large\"", StringComparison.Ordinal); if (idx > -1) { if (string.IsNullOrEmpty(Width)) { Width = "640"; } if (string.IsNullOrEmpty(Height)) { Height = "360"; } } else { idx = e.Result.IndexOf("thumbnail_medium", idx); if (idx > -1) { if (string.IsNullOrEmpty(Width)) { Width = "200"; } if (string.IsNullOrEmpty(Height)) { Height = "150"; } } else { idx = e.Result.IndexOf("thumbnail_small", idx); if (string.IsNullOrEmpty(Width)) { Width = "100"; } if (string.IsNullOrEmpty(Height)) { Height = "75"; } } } if (idx > -1) { idx = e.Result.IndexOf("http:", idx); if (idx > -1) { var endIdx = e.Result.IndexOf('"', idx); if (endIdx > -1) { _videoImageUrl = e.Result.Substring(idx, endIdx - idx).Replace("\\\"", "\"").Replace("\\", ""); } } } idx = e.Result.IndexOf("\"url\"", StringComparison.Ordinal); if (idx > -1) { idx = e.Result.IndexOf("http:", idx); if (idx > -1) { var endIdx = e.Result.IndexOf('"', idx); if (endIdx > -1) { _videoLinkUrl = e.Result.Substring(idx, endIdx - idx).Replace("\\\"", "\"").Replace("\\", ""); } } } } else { HandleDataLoadFailure(e.Error, "Vimeo"); } } } catch (Exception ex) { HtmlContainer.ReportError(HtmlRenderErrorType.Iframe, "Failed to parse Vimeo video response", ex); } HandlePostApiCall(sender); }
/// <summary> /// Parse YouTube API response to get video data (title, image, link). /// </summary> private void OnDownloadYoutubeApiCompleted(object sender, DownloadStringCompletedEventArgs e) { try { if (!e.Cancelled) { if (e.Error == null) { var idx = e.Result.IndexOf("\"media$title\"", StringComparison.Ordinal); if (idx > -1) { idx = e.Result.IndexOf("\"$t\"", idx); if (idx > -1) { idx = e.Result.IndexOf('"', idx + 4); if (idx > -1) { var endIdx = e.Result.IndexOf('"', idx + 1); while (e.Result[endIdx - 1] == '\\') { endIdx = e.Result.IndexOf('"', endIdx + 1); } if (endIdx > -1) { _videoTitle = e.Result.Substring(idx + 1, endIdx - idx - 1).Replace("\\\"", "\""); } } } } idx = e.Result.IndexOf("\"media$thumbnail\"", StringComparison.Ordinal); if (idx > -1) { var iidx = e.Result.IndexOf("sddefault", idx); if (iidx > -1) { if (string.IsNullOrEmpty(Width)) { Width = "640px"; } if (string.IsNullOrEmpty(Height)) { Height = "480px"; } } else { iidx = e.Result.IndexOf("hqdefault", idx); if (iidx > -1) { if (string.IsNullOrEmpty(Width)) { Width = "480px"; } if (string.IsNullOrEmpty(Height)) { Height = "360px"; } } else { iidx = e.Result.IndexOf("mqdefault", idx); if (iidx > -1) { if (string.IsNullOrEmpty(Width)) { Width = "320px"; } if (string.IsNullOrEmpty(Height)) { Height = "180px"; } } else { iidx = e.Result.IndexOf("default", idx); if (string.IsNullOrEmpty(Width)) { Width = "120px"; } if (string.IsNullOrEmpty(Height)) { Height = "90px"; } } } } iidx = e.Result.LastIndexOf("http:", iidx, StringComparison.Ordinal); if (iidx > -1) { var endIdx = e.Result.IndexOf('"', iidx); if (endIdx > -1) { _videoImageUrl = e.Result.Substring(iidx, endIdx - iidx).Replace("\\\"", "\"").Replace("\\", ""); } } } idx = e.Result.IndexOf("\"link\"", StringComparison.Ordinal); if (idx > -1) { idx = e.Result.IndexOf("http:", idx); if (idx > -1) { var endIdx = e.Result.IndexOf('"', idx); if (endIdx > -1) { _videoLinkUrl = e.Result.Substring(idx, endIdx - idx).Replace("\\\"", "\"").Replace("\\", ""); } } } } else { HandleDataLoadFailure(e.Error, "YouTube"); } } } catch (Exception ex) { HtmlContainer.ReportError(HtmlRenderErrorType.Iframe, "Failed to parse YouTube video response", ex); } HandlePostApiCall(sender); }
/// <summary> /// Load the stylesheet from local file by given path. /// </summary> /// <param name="htmlContainer">the container of the html to handle load stylesheet for</param> /// <param name="path">the stylesheet file to load</param> /// <returns>the loaded stylesheet string</returns> private static string LoadStylesheetFromFile(HtmlContainer htmlContainer, string path) { var fileInfo = CommonUtils.TryGetFileInfo(path); if (fileInfo != null) { if (fileInfo.Exists) { using (var sr = new StreamReader(fileInfo.FullName)) { return sr.ReadToEnd(); } } else { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "No stylesheet found by path: " + path); } } else { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Failed load image, invalid source: " + path); } return string.Empty; }
/// <summary> /// Show context menu clicked on given rectangle. /// </summary> /// <param name="parent">the parent control to show the context menu on</param> /// <param name="rect">the rectangle that was clicked to show context menu</param> /// <param name="link">the link that was clicked to show context menu on</param> public void ShowContextMenu(Control parent, CssRect rect, CssBox link) { try { DisposeContextMenu(); _parentControl = parent; _currentRect = rect; _currentLink = link; _contextMenu = new ContextMenuStrip(); _contextMenu.ShowImageMargin = false; if (rect != null) { bool isVideo = false; if (link != null) { isVideo = link is CssBoxFrame && ((CssBoxFrame)link).IsVideo; var openLink = _contextMenu.Items.Add(isVideo ? _openVideo : _openLink, null, OnOpenLinkClick); if (_htmlContainer.IsSelectionEnabled) { var copyLink = _contextMenu.Items.Add(isVideo ? _copyVideoUrl : _copyLink, null, OnCopyLinkClick); copyLink.Enabled = !string.IsNullOrEmpty(link.HrefLink); } openLink.Enabled = !string.IsNullOrEmpty(link.HrefLink); _contextMenu.Items.Add("-"); } if (rect.IsImage && !isVideo) { var saveImage = _contextMenu.Items.Add(_saveImage, null, OnSaveImageClick); if (_htmlContainer.IsSelectionEnabled) { var copyImageUrl = _contextMenu.Items.Add(_copyImageLink, null, OnCopyImageLinkClick); var copyImage = _contextMenu.Items.Add(_copyImage, null, OnCopyImageClick); copyImageUrl.Enabled = !string.IsNullOrEmpty(_currentRect.OwnerBox.GetAttribute("src")); copyImage.Enabled = rect.Image != null; } saveImage.Enabled = rect.Image != null; _contextMenu.Items.Add("-"); } if (_htmlContainer.IsSelectionEnabled) { var copy = _contextMenu.Items.Add(_copy, null, OnCopyClick); copy.Enabled = rect.Selected; } } if (_htmlContainer.IsSelectionEnabled) { _contextMenu.Items.Add(_selectAll, null, OnSelectAllClick); } if (_contextMenu.Items.Count > 0) { if (_contextMenu.Items[_contextMenu.Items.Count - 1].Text == string.Empty) { _contextMenu.Items.RemoveAt(_contextMenu.Items.Count - 1); } _contextMenu.Show(parent, parent.PointToClient(Control.MousePosition)); } } catch (Exception ex) { _htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to show context menu", ex); } }
/// <summary> /// Set image of this image box by analyzing the src attribute.<br/> /// Load the image from inline base64 encoded string.<br/> /// Or from calling property/method on the bridge object that returns image or url to image.<br/> /// Or from file path<br/> /// Or from URI. /// </summary> /// <remarks> /// File path and URI image loading is executed async and after finishing calling <see cref="ImageLoadComplete"/> /// on the main thread and not thread-pool. /// </remarks> /// <param name="htmlContainer">the container of the html to handle load image for</param> /// <param name="src">the source of the image to load</param> /// <param name="attributes">the collection of attributes on the element to use in event</param> /// <returns>the image object (null if failed)</returns> public void LoadImage(HtmlContainer htmlContainer, string src, Dictionary<string, string> attributes) { ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer"); _htmlContainer = htmlContainer; try { var args = new HtmlImageLoadEventArgs(src, attributes, OnHtmlImageLoadEventCallback); _htmlContainer.RaiseHtmlImageLoadEvent(args); _asyncCallback = true; if (!args.Handled) { if (!string.IsNullOrEmpty(src)) { if (src.StartsWith("data:image", StringComparison.CurrentCultureIgnoreCase)) { _image = GetImageFromData(src); if (_image == null) _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Failed extract image from inline data"); _releaseImageObject = true; ImageLoadComplete(false); } else { SetImageFromPath(src); } } else { ImageLoadComplete(false); } } } catch (Exception ex) { _htmlContainer.ReportError(HtmlRenderErrorType.Image, "Exception in handling image source", ex); ImageLoadComplete(false); } }