private List <IPage> UpdateItems(IEnumerable <IPage> pages)
        {
            OnPaneContentsChanging(pages.Any());
            var result        = new List <IPage>();
            var firstRealPage = pages.FirstOrDefault(p => p.Book != null);

            if (firstRealPage == null)
            {
                _browser.Navigate(@"about:blank", false);                 // no pages, we just want a blank screen, if anything.
                return(result);
            }
            var frame     = BloomFileLocator.GetBrowserFile(false, "bookEdit", "pageThumbnailList", "pageThumbnailList.html");
            var backColor = ColorToHtmlCode(BackColor);
            var htmlText  = RobustFile.ReadAllText(frame, Encoding.UTF8).Replace("DarkGray", backColor);

            _usingTwoColumns = RoomForTwoColumns;
            if (!RoomForTwoColumns)
            {
                htmlText = htmlText.Replace("columns: 4", "columns: 2").Replace("<div class=\"gridItem placeholder\" id=\"placeholder\"></div>", "");
            }
            var dom = new HtmlDom(XmlHtmlConverter.GetXmlDomFromHtml(htmlText));

            dom = firstRealPage.Book.GetHtmlDomReadyToAddPages(dom);
            var pageDoc = dom.RawDom;

            // BL-987: Add styles to optimize performance on Linux
            if (SIL.PlatformUtilities.Platform.IsLinux)
            {
                var style = pageDoc.CreateElement("style");
                style.InnerXml = "img { image-rendering: optimizeSpeed; image-rendering: -moz-crisp-edges; image-rendering: crisp-edges; }";
                pageDoc.GetElementsByTagName("head")[0].AppendChild(style);
            }

            var body         = pageDoc.GetElementsByTagName("body")[0];
            var gridlyParent = body.SelectSingleNode("//*[@id='pageGrid']");
            int pageNumber   = 0;

            _pageMap.Clear();
            foreach (var page in pages)
            {
                var pageElement = page.GetDivNodeForThisPage();
                if (pageElement == null)
                {
                    continue;                     // or crash? How can this happen?
                }
                result.Add(page);
                XmlElement pageElementForThumbnail = null;
                var        pageClasses             = pageElement.GetStringAttribute("class").Split(new[] { ' ' });
                var        cssClass = pageClasses.FirstOrDefault(c => c.ToLowerInvariant().EndsWith("portrait") || c.ToLower().EndsWith("landscape"));
                if (!TroubleShooterDialog.MakeEmptyPageThumbnails)
                {
                    pageElementForThumbnail = pageDoc.ImportNode(pageElement, true) as XmlElement;

                    // BL-1112: Reduce size of images in page thumbnails.
                    // We are setting the src to empty so that we can use JavaScript to request the thumbnails
                    // in a controlled manner that should reduce the likelihood of not receiving the image quickly
                    // enough and displaying the alt text rather than the image.
                    DelayAllImageNodes(pageElementForThumbnail);
                }
                else
                {
                    // Just make a minimal placeholder to get the white border.
                    pageElementForThumbnail = pageDoc.CreateElement("div");
                    var pageClass = "bloom-page";
                    // The page needs to have one of the classes like A4Portrait or it will have zero size and vanish.
                    if (!string.IsNullOrEmpty(cssClass))
                    {
                        pageClass += " " + cssClass;
                    }
                    pageElementForThumbnail.SetAttribute("class", pageClass);
                }

                var cellDiv = pageDoc.CreateElement("div");
                cellDiv.SetAttribute("class", ClassForGridItem);
                var gridId = GridId(page);
                cellDiv.SetAttribute("id", gridId);
                _pageMap.Add(gridId, page);
                gridlyParent.AppendChild(cellDiv);


                //we wrap our incredible-shrinking page in a plain 'ol div so that we
                //have something to give a border to when this page is selected
                var pageContainer = pageDoc.CreateElement("div");
                pageContainer.SetAttribute("class", PageContainerClass);
                pageContainer.AppendChild(pageElementForThumbnail);
                // We need an invisible div covering our pageContainer, so that the user can't actually click
                // on the underlying "incredible-shrinking page".
                var invisibleCover = pageDoc.CreateElement("div");
                invisibleCover.SetAttribute("class", InvisbleThumbClass);
                pageContainer.AppendChild(invisibleCover);

                // And here it gets fragile(for not).
                // The nature of how we're doing the thumbnails (relying on scaling) seems to mess up
                // the browser's normal ability to assign a width to the parent div. So our parent
                // here, .pageContainer, doesn't grow with the size of its child. Sigh. So for the
                // moment, we assign appropriate sizes, by hand.We rely on c# code to add these
                // classes, since we can't write a rule in css3 that peeks into a child attribute.

                if (!string.IsNullOrEmpty(cssClass))
                {
                    pageContainer.SetAttribute("class", "pageContainer " + cssClass);
                }

                cellDiv.AppendChild(pageContainer);
                var captionDiv = pageDoc.CreateElement("div");
                captionDiv.SetAttribute("class", "thumbnailCaption");
                cellDiv.AppendChild(captionDiv);
                string captionI18nId;
                var    captionOrPageNumber = page.GetCaptionOrPageNumber(ref pageNumber, out captionI18nId);
                if (!string.IsNullOrEmpty(captionOrPageNumber))
                {
                    captionDiv.InnerText = I18NHandler.GetTranslationDefaultMayNotBeEnglish(captionI18nId, captionOrPageNumber);
                }
            }

            // set interval based on physical RAM
            var intervalAttrib = pageDoc.CreateAttribute("data-thumbnail-interval");

            intervalAttrib.Value = _thumbnailInterval;
            body.Attributes.Append(intervalAttrib);

            _browser.WebBrowser.DocumentCompleted += WebBrowser_DocumentCompleted;
            // Save the scroll position of the thumbnail list to restore in WebBrowser_DocumentCompleted.
            // Note that the position we want is NOT _browser.VerticalScrollDistance (as in previous code),
            // since the actual list of pages is no longer the whole content of this browser; the
            // page controls are at the bottom and don't scroll. So we need the scroll position of
            // the element that overflows and scrolls.
            // it's awkward that we have to convert to a string and back, but the current version of
            // RunJavaScript does not support returning anything but strings.
            // (The TryParse is probably not necessary...in an early version of this code I was getting
            // nulls back sometimes, it may no longer be possible.)
            int.TryParse(_browser.RunJavaScript("(document.getElementById('pageGridWrapper')) ? document.getElementById('pageGridWrapper').scrollTop.toString() : '0'"), out _verticalScrollDistance);
            _baseForRelativePaths = dom.BaseForRelativePaths;
            _browser.Navigate(dom, source: "pagelist");
            return(result);
        }
        private List <IPage> UpdateItems(IEnumerable <IPage> pages)
        {
            RemoveThumbnailListeners();
            var result        = new List <IPage>();
            var firstRealPage = pages.FirstOrDefault(p => p.Book != null);

            if (firstRealPage == null)
            {
                _browser.Navigate(@"about:blank", false);                 // no pages, we just want a blank screen, if anything.
                return(result);
            }
            var frame     = BloomFileLocator.GetBrowserFile("bookEdit", "pageThumbnailList", "pageThumbnailList.html");
            var backColor = ColorToHtmlCode(BackColor);
            var htmlText  = RobustFile.ReadAllText(frame, Encoding.UTF8).Replace("DarkGray", backColor);

            _usingTwoColumns = RoomForTwoColumns;
            if (!RoomForTwoColumns)
            {
                htmlText = htmlText.Replace("columns: 4", "columns: 2").Replace("<div class=\"gridItem placeholder\" id=\"placeholder\"></div>", "");
            }
            var dom = new HtmlDom(XmlHtmlConverter.GetXmlDomFromHtml(htmlText));

            dom = firstRealPage.Book.GetHtmlDomReadyToAddPages(dom);
            var pageDoc = dom.RawDom;

            // BL-987: Add styles to optimize performance on Linux
            if (SIL.PlatformUtilities.Platform.IsLinux)
            {
                var style = pageDoc.CreateElement("style");
                style.InnerXml = "img { image-rendering: optimizeSpeed; image-rendering: -moz-crisp-edges; image-rendering: crisp-edges; }";
                pageDoc.GetElementsByTagName("head")[0].AppendChild(style);
            }

            var body         = pageDoc.GetElementsByTagName("body")[0];
            var gridlyParent = body.SelectSingleNode("//*[@id='pageGrid']");
            int pageNumber   = 0;

            _pageMap.Clear();
            foreach (var page in pages)
            {
                var pageElement = page.GetDivNodeForThisPage();
                if (pageElement == null)
                {
                    continue;                     // or crash? How can this happen?
                }
                result.Add(page);
                var pageElementForThumbnail = pageDoc.ImportNode(pageElement, true) as XmlElement;

                // BL-1112: Reduce size of images in page thumbnails.
                // We are setting the src to empty so that we can use JavaScript to request the thumbnails
                // in a controlled manner that should reduce the likelihood of not receiving the image quickly
                // enough and displaying the alt text rather than the image.
                DelayAllImageNodes(pageElementForThumbnail);

                var cellDiv = pageDoc.CreateElement("div");
                cellDiv.SetAttribute("class", ClassForGridItem);
                var gridId = GridId(page);
                cellDiv.SetAttribute("id", gridId);
                _pageMap.Add(gridId, page);
                gridlyParent.AppendChild(cellDiv);


                //we wrap our incredible-shrinking page in a plain 'ol div so that we
                //have something to give a border to when this page is selected
                var pageContainer = pageDoc.CreateElement("div");
                pageContainer.SetAttribute("class", PageContainerClass);
                pageContainer.AppendChild(pageElementForThumbnail);

                /* And here it gets fragile (for not).
                 *      The nature of how we're doing the thumbnails (relying on scaling) seems to mess up
                 *      the browser's normal ability to assign a width to the parent div. So our parent
                 *      here, .pageContainer, doesn't grow with the size of its child. Sigh. So for the
                 *      moment, we assign appropriate sizes, by hand. We rely on c# code to add these
                 *      classes, since we can't write a rule in css3 that peeks into a child attribute.
                 */
                var pageClasses = pageElementForThumbnail.GetStringAttribute("class").Split(new[] { ' ' });
                var cssClass    = pageClasses.FirstOrDefault(c => c.ToLowerInvariant().EndsWith("portrait") || c.ToLower().EndsWith("landscape"));
                if (!string.IsNullOrEmpty(cssClass))
                {
                    pageContainer.SetAttribute("class", "pageContainer " + cssClass);
                }

                cellDiv.AppendChild(pageContainer);
                var captionDiv = pageDoc.CreateElement("div");
                captionDiv.SetAttribute("class", "thumbnailCaption");
                cellDiv.AppendChild(captionDiv);
                string captionI18nId;
                var    captionOrPageNumber = page.GetCaptionOrPageNumber(ref pageNumber, out captionI18nId);
                if (!string.IsNullOrEmpty(captionOrPageNumber))
                {
                    captionDiv.InnerText = I18NHandler.GetTranslationDefaultMayNotBeEnglish(captionI18nId, captionOrPageNumber);
                }
            }

            // set interval based on physical RAM
            var intervalAttrib = pageDoc.CreateAttribute("data-thumbnail-interval");

            intervalAttrib.Value = _thumbnailInterval;
            body.Attributes.Append(intervalAttrib);

            _browser.WebBrowser.DocumentCompleted += WebBrowser_DocumentCompleted;
            _verticalScrollDistance = _browser.VerticalScrollDistance;
            _baseForRelativePaths   = dom.BaseForRelativePaths;
            _browser.Navigate(dom);
            return(result);
        }
        private List <IPage> UpdateItems(IEnumerable <IPage> pages)
        {
            var result    = new List <IPage>();
            var frame     = BloomFileLocator.GetFileDistributedWithApplication("BloomBrowserUI", "bookEdit", "BookPagesThumbnailList", "BookPagesThumbnailList.htm");
            var backColor = ColorToHtmlCode(BackColor);
            var htmlText  = System.IO.File.ReadAllText(frame, Encoding.UTF8).Replace("DarkGray", backColor);

            _usingTwoColumns = RoomForTwoColumns;
            if (!RoomForTwoColumns)
            {
                htmlText = htmlText.Replace("columns: 4", "columns: 2").Replace("<div class=\"gridItem placeholder\" id=\"placeholder\"></div>", "");
            }
            var dom           = new HtmlDom(htmlText);
            var firstRealPage = pages.FirstOrDefault(p => p.Book != null);

            if (firstRealPage == null)
            {
                _browser.Navigate(@"about:blank", false);                 // no pages, we just want a blank screen, if anything.
                return(result);
            }
            dom = firstRealPage.Book.GetHtmlDomReadyToAddPages(dom);
            var pageDoc      = dom.RawDom;
            var body         = pageDoc.GetElementsByTagName("body")[0];
            var gridlyParent = body.FirstChild;             // too simplistic?
            int pageNumber   = 0;

            _pageMap.Clear();
            foreach (var page in pages)
            {
                var node = page.GetDivNodeForThisPage();
                if (node == null)
                {
                    continue;                     // or crash? How can this happen?
                }
                result.Add(page);
                var pageThumbnail = pageDoc.ImportNode(node, true);
                var cellDiv       = pageDoc.CreateElement("div");
                cellDiv.SetAttribute("class", "gridItem");
                var gridId = GridId(page);
                cellDiv.SetAttribute("id", gridId);
                _pageMap[gridId] = page;
                gridlyParent.AppendChild(cellDiv);


                //we wrap our incredible-shrinking page in a plain 'ol div so that we
                //have something to give a border to when this page is selected
                var pageContainer = pageDoc.CreateElement("div");
                pageContainer.SetAttribute("class", "pageContainer");
                pageContainer.AppendChild(pageThumbnail);


                /* And here it gets fragile (for not).
                 * The nature of how we're doing the thumbnails (relying on scaling) seems to mess up
                 *      the browser's normal ability to assign a width to the parent div. So our parent
                 *      here, .pageContainer, doesn't grow with the size of its child. Sigh. So for the
                 *      moment, we assign appropriate sizes, by hand. We rely on c# code to add these
                 *      classes, since we can't write a rule in css3 that peeks into a child attribute.
                 */
                var pageClasses = pageThumbnail.GetStringAttribute("class");

                //enhance: there is doubtless code somewhere else that picks these size/orientations out elegantly
                if (pageClasses.ToLower().Contains("a5portrait"))
                {
                    pageContainer.SetAttribute("class", "pageContainer A5Portrait");
                }
                if (pageClasses.ToLower().Contains("a4portrait"))
                {
                    pageContainer.SetAttribute("class", "pageContainer A4Portrait");
                }
                if (pageClasses.ToLower().Contains("a4landscape"))
                {
                    pageContainer.SetAttribute("class", "pageContainer A4Landscape");
                }

                cellDiv.AppendChild(pageContainer);
                var captionDiv = pageDoc.CreateElement("div");
                captionDiv.SetAttribute("class", "thumbnailCaption");
                cellDiv.AppendChild(captionDiv);
                var captionOrPageNumber = page.GetCaptionOrPageNumber(ref pageNumber);
                captionDiv.InnerText = LocalizationManager.GetDynamicString("Bloom", "EditTab.ThumbnailCaptions." + captionOrPageNumber, captionOrPageNumber);
            }
            _browser.WebBrowser.DocumentCompleted += WebBrowser_DocumentCompleted;
            _verticalScrollDistance = _browser.VerticalScrollDistance;
            _browser.Navigate(pageDoc, null);
            return(result);
        }