HtmlFrameElementBase
Represents the base class for frame elements.
using AngleSharp.Extensions;
using AngleSharp.Html;
using AngleSharp.Network;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AngleSharp.Dom.Html
{
internal abstract class HtmlFrameElementBase : HtmlFrameOwnerElement
{
private sealed class FrameElementRequest
{
private readonly Document _document;
private readonly HtmlFrameElementBase _element;
private readonly IBrowsingContext _context;
private readonly string _htmlContent;
private readonly string _requestUrl;
private readonly CancellationTokenSource _cts;
private IDownload _download;
public FrameElementRequest(Document document, HtmlFrameElementBase element, IBrowsingContext context, string htmlContent, string requestUrl)
{
_document = document;
_element = element;
_context = context;
_htmlContent = htmlContent;
_requestUrl = requestUrl;
_cts = new CancellationTokenSource();
}
public async Task Perform(Action<IDocument> callback)
{
callback(await GetDocumentAsync().ConfigureAwait(false));
}
public void Cancel()
{
_cts.Cancel();
}
private async Task<IDocument> GetDocumentAsync()
{
string referer = _document.DocumentUri;
IResourceLoader loader = _document.Loader;
if (_htmlContent == null && !string.IsNullOrEmpty(_requestUrl) && !_requestUrl.Is(_element.BaseUri) && loader != null) {
CancellationToken cancel = _cts.Token;
ResourceRequest request = ElementExtensions.CreateRequestFor(url: _element.HyperReference(_requestUrl), element: _element);
_download = loader.DownloadAsync(request);
IDownload download = _download;
cancel.Register(download.Cancel);
return await BrowsingContextExtensions.OpenAsync(response: await _download.Task.ConfigureAwait(false), context: _context, cancel: cancel).ConfigureAwait(false);
}
return await _context.OpenAsync(delegate(BrowsingContextExtensions.VirtualResponse m) {
m.Content(_htmlContent).Address(referer);
}, _cts.Token).ConfigureAwait(false);
}
}
private IBrowsingContext _context;
private FrameElementRequest _download;
public string Name {
get {
return this.GetOwnAttribute(AttributeNames.Name);
}
set {
this.SetOwnAttribute(AttributeNames.Name, value);
}
}
public string Source {
get {
return this.GetUrlAttribute(AttributeNames.Src);
}
set {
this.SetOwnAttribute(AttributeNames.Src, value);
}
}
public string Scrolling {
get {
return this.GetOwnAttribute(AttributeNames.Scrolling);
}
set {
this.SetOwnAttribute(AttributeNames.Scrolling, value);
}
}
public IDocument ContentDocument { get; set; }
public string LongDesc {
get {
return this.GetOwnAttribute(AttributeNames.LongDesc);
}
set {
this.SetOwnAttribute(AttributeNames.LongDesc, value);
}
}
public string FrameBorder {
get {
return this.GetOwnAttribute(AttributeNames.FrameBorder);
}
set {
this.SetOwnAttribute(AttributeNames.FrameBorder, value);
}
}
protected IBrowsingContext NestedContext => _context ?? (_context = base.Owner.NewChildContext(Sandboxes.None));
public HtmlFrameElementBase(Document owner, string name, string prefix, NodeFlags flags = NodeFlags.None)
: base(owner, name, prefix, flags | NodeFlags.Special)
{
}
protected virtual string GetContentHtml()
{
return null;
}
protected void UpdateSource(string _)
{
if (_download != null)
_download.Cancel();
string contentHtml = GetContentHtml();
string source = Source;
Document owner = base.Owner;
if ((source != null || contentHtml != null) && owner != null) {
FrameElementRequest frameElementRequest = new FrameElementRequest(owner, this, NestedContext, contentHtml, source);
Task task = frameElementRequest.Perform(delegate(IDocument result) {
ContentDocument = result;
});
owner.DelayLoad(task);
_download = frameElementRequest;
}
}
internal override void SetupElement()
{
base.SetupElement();
string ownAttribute = this.GetOwnAttribute(AttributeNames.Src);
RegisterAttributeObserver(AttributeNames.Src, UpdateSource);
if (ownAttribute != null)
UpdateSource(ownAttribute);
}
}
}