예제 #1
0
        /// <summary>
        /// Executes a function in browser context
        /// </summary>
        /// <typeparam name="T">The type to deserialize the result to</typeparam>
        /// <param name="script">Script to be evaluated in browser context</param>
        /// <param name="args">Arguments to pass to script</param>
        /// <remarks>
        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
        /// <see cref="JSHandle"/> instances can be passed as arguments
        /// </remarks>
        /// <returns>Task which resolves to script return value</returns>
        public Task <T> EvaluateFunctionAsync <T>(string script, params object[] args)
        {
            var list = new List <object>(args);

            list.Insert(0, this);
            return(ExecutionContext.EvaluateFunctionAsync <T>(script, list.ToArray()));
        }
예제 #2
0
        private async Task ScrollIntoViewIfNeededAsync()
        {
            var errorMessage = await ExecutionContext.EvaluateFunctionAsync <string>(@"async(element, pageJavascriptEnabled) => {
              if (!element.isConnected)
                return 'Node is detached from document';
              if (element.nodeType !== Node.ELEMENT_NODE)
                return 'Node is not of type HTMLElement';
              // force-scroll if page's javascript is disabled.
              if (!pageJavascriptEnabled) {
                element.scrollIntoView({block: 'center', inline: 'center', behavior: 'instant'});
                return false;
              }
              const visibleRatio = await new Promise(resolve => {
                const observer = new IntersectionObserver(entries => {
                  resolve(entries[0].intersectionRatio);
                  observer.disconnect();
                });
                observer.observe(element);
              });
              if (visibleRatio !== 1.0)
                element.scrollIntoView({block: 'center', inline: 'center', behavior: 'instant'});
              return false;
            }", this, Page.JavascriptEnabled).ConfigureAwait(false);

            if (errorMessage != null)
            {
                throw new PuppeteerException(errorMessage);
            }
        }
예제 #3
0
        /// <summary>
        /// This method scrolls element into view if needed, and then uses <seealso cref="Page.ScreenshotBase64Async(ScreenshotOptions)"/> to take a screenshot of the element.
        /// If the element is detached from DOM, the method throws an error.
        /// </summary>
        /// <returns>Task which resolves to a <see cref="string"/> containing the image data as base64.</returns>
        /// <param name="options">Screenshot options.</param>
        public async Task <string> ScreenshotBase64Async(ScreenshotOptions options)
        {
            var needsViewportReset = false;
            var boundingBox        = await BoundingBoxAsync().ConfigureAwait(false);

            if (boundingBox == null)
            {
                throw new PuppeteerException("Node is either not visible or not an HTMLElement");
            }

            var viewport = Page.Viewport;

            if (viewport != null && (boundingBox.Width > viewport.Width || boundingBox.Height > viewport.Height))
            {
                var newRawViewport = JObject.FromObject(viewport);
                newRawViewport.Merge(new ViewPortOptions
                {
                    Width  = (int)Math.Max(viewport.Width, Math.Ceiling(boundingBox.Width)),
                    Height = (int)Math.Max(viewport.Height, Math.Ceiling(boundingBox.Height))
                });
                await Page.SetViewportAsync(newRawViewport.ToObject <ViewPortOptions>()).ConfigureAwait(false);

                needsViewportReset = true;
            }
            await ExecutionContext.EvaluateFunctionAsync(@"function(element) {
                element.scrollIntoView({ block: 'center', inline: 'center', behavior: 'instant'});
            }", this).ConfigureAwait(false);

            await ScrollIntoViewIfNeededAsync().ConfigureAwait(false);

            boundingBox = await BoundingBoxAsync().ConfigureAwait(false);

            if (boundingBox == null)
            {
                throw new PuppeteerException("Node is either not visible or not an HTMLElement");
            }
            var getLayoutMetricsResponse = await Client.SendAsync <GetLayoutMetricsResponse>("Page.getLayoutMetrics").ConfigureAwait(false);

            var clip = boundingBox;

            clip.X += getLayoutMetricsResponse.LayoutViewport.PageX;
            clip.Y += getLayoutMetricsResponse.LayoutViewport.PageY;

            options.Clip = boundingBox.ToClip();
            var imageData = await Page.ScreenshotBase64Async(options).ConfigureAwait(false);

            if (needsViewportReset)
            {
                await Page.SetViewportAsync(viewport).ConfigureAwait(false);
            }

            return(imageData);
        }
예제 #4
0
 /// <summary>
 /// Evaluates if the element is visible in the current viewport.
 /// </summary>
 /// <returns>A task which resolves to true if the element is visible in the current viewport.</returns>
 public Task <bool> IsIntersectingViewportAsync()
 => ExecutionContext.EvaluateFunctionAsync <bool>(@"async element =>
     {
         const visibleRatio = await new Promise(resolve =>
         {
             const observer = new IntersectionObserver(entries =>
             {
                 resolve(entries[0].intersectionRatio);
                 observer.disconnect();
             });
             observer.observe(element);
         });
         return visibleRatio > 0;
     }", this);
예제 #5
0
        private async Task ScrollIntoViewIfNeededAsync()
        {
            var errorMessage = await ExecutionContext.EvaluateFunctionAsync <string>(@"element => {
                if (!element.isConnected)
                    return 'Node is detached from document';
                if (element.nodeType !== Node.ELEMENT_NODE)
                    return 'Node is not of type HTMLElement';
                element.scrollIntoViewIfNeeded();
                return null;
            }", this);

            if (errorMessage != null)
            {
                throw new PuppeteerException(errorMessage);
            }
        }
예제 #6
0
        /// <summary>
        /// This method scrolls element into view if needed, and then uses <seealso cref="Page.ScreenshotDataAsync(ScreenshotOptions)"/> to take a screenshot of the element.
        /// If the element is detached from DOM, the method throws an error.
        /// </summary>
        /// <returns>Task which resolves to a <see cref="byte"/>[] containing the image data.</returns>
        /// <param name="options">Screenshot options.</param>
        public async Task <byte[]> ScreenshotDataAsync(ScreenshotOptions options)
        {
            var needsViewportReset = false;
            var boundingBox        = await AssertBoundingBoxAsync();

            var viewport = Page.Viewport;

            if (boundingBox.Width > viewport.Width || boundingBox.Height > viewport.Height)
            {
                var newRawViewport = JObject.FromObject(viewport);
                newRawViewport.Merge(new ViewPortOptions
                {
                    Width  = (int)Math.Max(viewport.Width, Math.Ceiling(boundingBox.Width)),
                    Height = (int)Math.Max(viewport.Height, Math.Ceiling(boundingBox.Height))
                });
                await Page.SetViewportAsync(newRawViewport.ToObject <ViewPortOptions>());

                needsViewportReset = true;
            }
            await ExecutionContext.EvaluateFunctionAsync(@"function(element) {
                element.scrollIntoView({ block: 'center', inline: 'center', behavior: 'instant'});
            }", this);

            boundingBox = await AssertBoundingBoxAsync();

            var getLayoutMetricsResponse = await Client.SendAsync <GetLayoutMetricsResponse>("Page.getLayoutMetrics");

            var clip = boundingBox;

            clip.X += getLayoutMetricsResponse.LayoutViewport.PageX;
            clip.Y += getLayoutMetricsResponse.LayoutViewport.PageY;

            options.Clip = boundingBox.ToClip();
            var imageData = await Page.ScreenshotDataAsync(options);

            if (needsViewportReset)
            {
                await Page.SetViewportAsync(viewport);
            }

            return(imageData);
        }
예제 #7
0
 /// <summary>
 /// Calls <c>focus</c> <see cref="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus"/> on the element.
 /// </summary>
 /// <returns>Task</returns>
 public Task FocusAsync() => ExecutionContext.EvaluateFunctionAsync("element => element.focus()", this);