示例#1
0
        //NB: make sure the <base> is set correctly, 'cause you don't know where this method will
        //save the file before navigating to it.
        public void Navigate(XmlDocument dom, XmlDocument editDom = null)
        {
            if (InvokeRequired)
            {
                Invoke(new Action <XmlDocument, XmlDocument>(Navigate), dom, editDom);
                return;
            }

            _rootDom     = dom;        //.CloneNode(true); //clone because we want to modify it a bit
            _pageEditDom = editDom ?? dom;

            /*	This doesn't work for the 1st book shown, or when you change book sizes.
             * But it's still worth doing, becuase without it, we have this annoying re-zoom every time we look at different page.
             */
            XmlElement body = (XmlElement)_rootDom.GetElementsByTagName("body")[0];

            if (ScaleToFullWidthOfPage)
            {
                var scale = GetScaleToShowWholeWidthOfPage();
                if (scale > 0f)
                {
                    body.SetAttribute("style", GetZoomCSS(scale));
                }
            }
            XmlHtmlConverter.MakeXmlishTagsSafeForInterpretationAsHtml(dom);
            SetNewTempFile(TempFileUtils.CreateHtm5FromXml(dom));
            _url = _tempHtmlFile.Path.ToLocalhost();
            UpdateDisplay();
        }
        public void CanRetrieveContentOfFakeTempFile_ButOnlyUntilDisposed()
        {
            using (var server = CreateImageServer())
            {
                var html = @"<html ><head></head><body>here it is</body></html>";
                var dom  = new HtmlDom(html);
                dom.BaseForRelativePaths = _folder.Path.ToLocalhost();
                string url;
                using (var fakeTempFile = EnhancedImageServer.MakeSimulatedPageFileInBookFolder(dom))
                {
                    url = fakeTempFile.Key;
                    var transaction = new PretendRequestInfo(url);

                    // Execute
                    server.MakeReply(transaction);

                    // Verify
                    // Whitespace inserted by CreateHtml5StringFromXml seems to vary across versions and platforms.
                    // I would rather verify the actual output, but don't want this test to be fragile, and the
                    // main point is that we get a file with the DOM content.
                    Assert.That(transaction.ReplyContents,
                                Is.EqualTo(TempFileUtils.CreateHtml5StringFromXml(dom.RawDom)));
                }
                var transactionFail = new PretendRequestInfo(url);

                // Execute
                server.MakeReply(transactionFail);

                // Verify
                Assert.That(transactionFail.StatusCode, Is.EqualTo(404));
            }
        }
示例#3
0
        public void StartMeasuring()
        {
            CurrentlyMeasuring = true;

            if (_stream != null)
            {
                _stream.Close();
                _stream.Dispose();
                // no, leave it and its contents around: _folder.Dispose();
            }

            _csvFilePath      = TempFileUtils.GetTempFilepathWithExtension(".csv");
            _stream           = RobustFile.CreateText(_csvFilePath);
            _stream.AutoFlush = true;

            try
            {
                _stream.WriteLine(Form.ActiveForm.Text);
            }
            catch (Exception)
            {
                // swallow. This happens when we call from firefox, while debugging.
            }
            using (Measure("Initial Memory Reading"))
            {
            }
        }
示例#4
0
        public static string MakeToolboxContent(Book.Book book)
        {
            var path          = BloomFileLocator.GetBrowserFile("bookEdit/toolbox", "toolbox.html");
            var toolboxFolder = Path.GetDirectoryName(path);

            var domForToolbox = new HtmlDom(XmlHtmlConverter.GetXmlDomFromHtmlFile(path));


            var toolsToDisplay = GetToolsToDisplay(book, IdsOfToolsThisVersionKnowsAbout);

            // get additional tools to load
            var checkedBoxes = new List <string>();

            foreach (var tool in toolsToDisplay)
            {
                LoadPanelIntoToolbox(domForToolbox, tool, checkedBoxes, toolboxFolder);
            }

            // Load settings into the toolbox panel
            AppendToolboxPanel(domForToolbox, BloomFileLocator.GetFileDistributedWithApplication(Path.Combine(toolboxFolder, "settings", "Settings.html")));

            // check the appropriate boxes
            foreach (var checkBoxId in checkedBoxes)
            {
                // Review: really? we have to use a special character to make a check? can't we add "checked" attribute?
                var node = domForToolbox.Body.SelectSingleNode("//div[@id='" + checkBoxId + "']");
                if (node != null)
                {
                    node.InnerXml = "&#10004;";
                }
            }

            XmlHtmlConverter.MakeXmlishTagsSafeForInterpretationAsHtml(domForToolbox.RawDom);
            return(TempFileUtils.CreateHtml5StringFromXml(domForToolbox.RawDom));
        }
示例#5
0
        public static string MakeToolboxContent(Book.Book book)
        {
            var path          = BloomFileLocator.GetBrowserFile(false, "bookEdit/toolbox", "toolbox.html");
            var domForToolbox = new HtmlDom(XmlHtmlConverter.GetXmlDomFromHtmlFile(path));

            XmlHtmlConverter.MakeXmlishTagsSafeForInterpretationAsHtml(domForToolbox.RawDom);
            return(TempFileUtils.CreateHtml5StringFromXml(domForToolbox.RawDom));
        }
 public void SetupServerWithCurrentPageIframeContents()
 {
     _domForCurrentPage = _bookSelection.CurrentSelection.GetEditableHtmlDomForPage(_pageSelection.CurrentSelection);
     XmlHtmlConverter.MakeXmlishTagsSafeForInterpretationAsHtml(_domForCurrentPage.RawDom);
     _server.CurrentPageContent = TempFileUtils.CreateHtml5StringFromXml(_domForCurrentPage.RawDom);
     _server.AccordionContent   = MakeAccordionContent();
     _server.CurrentBook        = _currentlyDisplayedBook;
 }
        public void CanRetrieveContentOfFakeTempFile_WhenFolderContainsAmpersand_NotViaJavaScript()
        {
            var dom         = SetupDomWithAmpersandInTitle();
            var transaction = CreateServerMakeSimPageMakeReply(dom);

            // Verify
            // Whitespace inserted by CreateHtml5StringFromXml seems to vary across versions and platforms.
            // I would rather verify the actual output, but don't want this test to be fragile, and the
            // main point is that we get a file with the DOM content.
            Assert.That(transaction.ReplyContents,
                        Is.EqualTo(TempFileUtils.CreateHtml5StringFromXml(dom.RawDom)));
        }
示例#8
0
        /// <summary>
        /// This code sets things up so that we can edit (or make a thumbnail of, etc.) one page of a book.
        /// This is tricky because we have to satisfy several constraints:
        /// - We need to make this page content the 'src' of an iframe in a browser. So it has to be
        /// locatable by url.
        /// - It needs to appear to the browser to be a document in the book's folder. This allows local
        /// hrefs (e.g., src of images) that are normally relative to the whole-book file to locate
        /// the images. (We previously did this by making a file elsewhere and setting the 'base'
        /// for interpreting urls. But this fails for internal hrefs (starting with #)).
        /// - We don't want to risk leaving junk page files in the real book folder if anything goes wrong.
        /// - There may be several of these simulated pages around at the same time (e.g., when the thumbnailer is
        /// working on several threads).
        /// - The simulated files need to hang around for an unpredictable time (until the browser is done
        /// with them).
        /// The solution we have adopted is to make this server simulate files in the book folder.
        /// That is, the src for the page iframe is set to a localhost: url which maps to a file in the
        /// book folder. This means that any local hrefs (e.g., to images) will become server requests
        /// for the right file in the right folder. However, the page file never exists as a real file
        /// system file; instead, a request for the page file itself will be intercepted, and this server
        /// simply returns the content it has remembered.
        /// To manage the lifetime of the page data, we use a SimulatedPageFile object, which the Browser
        /// disposes of when it is no longer looking at that URL. Its dispose method tells this class
        /// to discard the simulated page data.
        /// To handle the need for multiple simulated page files and quickly check whether a particular
        /// url is one of them, we have a dictionary in which the urls are keys.
        /// A marker is inserted into the generated urls if the input HtmlDom wants to use original images.
        /// </summary>
        /// <param name="dom"></param>
        /// <param name="isCurrentPageContent">If this is true, the url will be inserted by JavaScript into
        /// a src attr for an IFrame. We need to account for this because un-escaped quotation marks in the
        /// URL can cause errors in JavaScript strings. Also, we want to use the same name each time
        /// for current page content, so Open Page in Browser works even after changing pages.</param>
        /// <returns></returns>
        public static SimulatedPageFile MakeSimulatedPageFileInBookFolder(HtmlDom dom, bool isCurrentPageContent = false, bool setAsCurrentPageForDebugging = false, string source = "")
        {
            var simulatedPageFileName   = Path.ChangeExtension((isCurrentPageContent ? "currentPage" : Guid.NewGuid().ToString()) + SimulatedFileUrlMarker + source, ".html");
            var pathToSimulatedPageFile = simulatedPageFileName;             // a default, if there is no special folder

            if (dom.BaseForRelativePaths != null)
            {
                pathToSimulatedPageFile = Path.Combine(dom.BaseForRelativePaths, simulatedPageFileName).Replace('\\', '/');
            }
            if (File.Exists(pathToSimulatedPageFile))
            {
                // Just in case someone perversely calls a book "currentPage" we will use another name.
                // (We want one that does NOT conflict with anything really in the folder.)
                // We only allow one HTML file per folder so we shouldn't need multiple attempts.
                pathToSimulatedPageFile = Path.Combine(dom.BaseForRelativePaths, "X" + simulatedPageFileName).Replace('\\', '/');
            }
            // FromLocalHost is smart about doing nothing if it is not a localhost url. In case it is, we
            // want the OriginalImageMarker (if any) after the localhost stuff.
            pathToSimulatedPageFile = pathToSimulatedPageFile.FromLocalhost();
            if (dom.UseOriginalImages)
            {
                pathToSimulatedPageFile = OriginalImageMarker + "/" + pathToSimulatedPageFile;
            }
            var url = pathToSimulatedPageFile.ToLocalhost();
            var key = pathToSimulatedPageFile.Replace('\\', '/');

            if (isCurrentPageContent)
            {
                // We need to UrlEncode the single and double quote characters, and the space character,
                // so they will play nicely with HTML.
                var urlPath = UrlPathString.CreateFromUnencodedString(url);
                url = urlPath.UrlEncodedForHttpPath;
            }
            if (setAsCurrentPageForDebugging)
            {
                _keyToCurrentPage = key;
            }
            var html5String = TempFileUtils.CreateHtml5StringFromXml(dom.RawDom);

            lock (_urlToSimulatedPageContent)
            {
                _urlToSimulatedPageContent[key] = html5String;
            }
            return(new SimulatedPageFile()
            {
                Key = url
            });
        }
示例#9
0
        /// <summary>
        /// This code sets things up so that we can edit (or make a thumbnail of, etc.) one page of a book.
        /// This is tricky because we have to satisfy several constraints:
        /// - We need to make this page content the 'src' of an iframe in a browser. So it has to be
        /// locatable by url.
        /// - It needs to appear to the browser to be a document in the book's folder. This allows local
        /// hrefs (e.g., src of images) that are normally relative to the whole-book file to locate
        /// the images. (We previously did this by making a file elsewhere and setting the 'base'
        /// for interpreting urls. But this fails for internal hrefs (starting with #)).
        /// - We don't want to risk leaving junk page files in the real book folder if anything goes wrong.
        /// - There may be several of these simulated pages around at the same time (e.g., when the thumbnailer is
        /// working on several threads).
        /// - The simulated files need to hang around for an unpredictable time (until the browser is done
        /// with them).
        /// The solution we have adopted is to make this server simulate files in the book folder.
        /// That is, the src for the page iframe is set to a localhost: url which maps to a file in the
        /// book folder. This means that any local hrefs (e.g., to images) will become server requests
        /// for the right file in the right folder. However, the page file never exists as a real file
        /// system file; instead, a request for the page file itself will be intercepted, and this server
        /// simply returns the content it has remembered.
        /// To manage the lifetime of the page data, we use a SimulatedPageFile object, which the Browser
        /// disposes of when it is no longer looking at that URL. Its dispose method tells this class
        /// to discard the simulated page data.
        /// To handle the need for multiple simulated page files and quickly check whether a particular
        /// url is one of them, we have a dictionary in which the urls are keys.
        /// A marker is inserted into the generated urls if the input HtmlDom wants to use original images.
        /// </summary>
        /// <param name="dom"></param>
        /// <param name="escapeUrlAsNeededForSrcAttribute">If this is true, the url will be inserted by JavaScript into
        /// a src attr for an IFrame. We need to account for this because un-escaped quotation marks in the
        /// URL can cause errors in JavaScript strings.</param>
        /// <returns></returns>
        public static SimulatedPageFile MakeSimulatedPageFileInBookFolder(HtmlDom dom, bool escapeUrlAsNeededForSrcAttribute = false, bool setAsCurrentPageForDebugging = false)
        {
            var simulatedPageFileName   = Path.ChangeExtension(Guid.NewGuid().ToString(), ".html");
            var pathToSimulatedPageFile = simulatedPageFileName;             // a default, if there is no special folder

            if (dom.BaseForRelativePaths != null)
            {
                pathToSimulatedPageFile = Path.Combine(dom.BaseForRelativePaths, simulatedPageFileName).Replace('\\', '/');
            }
            // FromLocalHost is smart about doing nothing if it is not a localhost url. In case it is, we
            // want the OriginalImageMarker (if any) after the localhost stuff.
            pathToSimulatedPageFile = pathToSimulatedPageFile.FromLocalhost();
            if (dom.UseOriginalImages)
            {
                pathToSimulatedPageFile = OriginalImageMarker + "/" + pathToSimulatedPageFile;
            }
            var url = pathToSimulatedPageFile.ToLocalhost();
            var key = pathToSimulatedPageFile.Replace('\\', '/');

            if (escapeUrlAsNeededForSrcAttribute)
            {
                // We need to UrlEncode the single and double quote characters so they will play nicely with JavaScript.
                url = EscapeUrlQuotes(url);
                // When JavaScript inserts our path into the html it replaces the three magic html characters with these substitutes.
                // We need to modify our key so that when the JavaScript comes looking for the page its modified url will
                // generate the right key.
                key = SimulateJavaScriptHandlingOfHtml(key);
            }
            if (setAsCurrentPageForDebugging)
            {
                _keyToCurrentPage = key;
            }
            var html5String = TempFileUtils.CreateHtml5StringFromXml(dom.RawDom);

            lock (_urlToSimulatedPageContent)
            {
                _urlToSimulatedPageContent[key] = html5String;
            }
            return(new SimulatedPageFile()
            {
                Key = url
            });
        }
示例#10
0
        /// <summary>
        /// Returns true if it make some attempt at an image, false if navigation is currently suppressed.
        /// </summary>
        /// <param name="order"></param>
        /// <param name="browser"></param>
        /// <param name="thumbnail"></param>
        /// <returns></returns>
        private bool CreateThumbNail(ThumbnailOrder order, GeckoWebBrowser browser, out Image thumbnail)
        {
            // runs on threadpool thread
            thumbnail = null;
            using (var temp = TempFileUtils.CreateHtm5FromXml(order.Document))
            {
                order.Done  = false;
                browser.Tag = order;
                if (!OpenTempFileInBrowser(browser, temp.Path))
                {
                    return(false);
                }

                var browserSize = SetWidthAndHeight(browser);
                if (browserSize.Height == 0)          //happens when we run into the as-yet-unreproduced-or-fixed bl-254
                {
                    return(false);                    // will try again later
                }
                try
                {
                    Logger.WriteMinorEvent("HtmlThumNailer ({2}): browser.GetBitmap({0},{1})", browserSize.Width,
                                           (uint)browserSize.Height,
                                           Thread.CurrentThread.ManagedThreadId);
                    //BUG (April 2013) found that the initial call to GetBitMap always had a zero width, leading to an exception which
                    //the user doesn't see and then all is well. So at the moment, we avoid the exception, and just leave with
                    //the placeholder thumbnail.
                    if (browserSize.Width == 0 || browserSize.Height == 0)
                    {
                        var paperSizeName = GetPaperSizeName(order.Document);
                        throw new ApplicationException("Problem getting thumbnail browser for document with Paper Size: " +
                                                       paperSizeName);
                    }
                    using (Image fullsizeImage = CreateImage(browser))
                    {
                        if (_disposed)
                        {
                            return(false);
                        }
                        thumbnail = MakeThumbNail(fullsizeImage, order.Options);
                        return(true);
                    }
                }
                catch (Exception error)
                {
                    Logger.WriteEvent("HtmlThumbNailer ({0}) got {1}", Thread.CurrentThread.ManagedThreadId, error.Message);
                    Logger.WriteEvent("Disposing of all browsers in hopes of getting a fresh start on life");
                    foreach (var browserCacheForDifferentPaperSize in _browserCacheForDifferentPaperSizes)
                    {
                        try
                        {
                            Logger.WriteEvent("Disposing of browser {0}", browserCacheForDifferentPaperSize.Key);
                            browserCacheForDifferentPaperSize.Value.Dispose();
                        }
                        catch (Exception e2)
                        {
                            Logger.WriteEvent(
                                "While trying to dispose of thumbnailer browsers as a result of an exception, go another: " + e2.Message);
                        }
                    }
                    _browserCacheForDifferentPaperSizes.Clear();
#if DEBUG
                    _syncControl.Invoke((Action)(() => Debug.Fail(error.Message)));
#endif
                }
            }
            return(false);
        }
示例#11
0
        private string MakeAccordionContent()
        {
            var path = FileLocator.GetFileDistributedWithApplication("BloomBrowserUI/bookEdit/accordion", "Accordion.htm");

            _accordionFolder = Path.GetDirectoryName(path);

            var domForAccordion = new HtmlDom(XmlHtmlConverter.GetXmlDomFromHtmlFile(path));

            // embed settings on the page
            var tools = _currentlyDisplayedBook.BookInfo.Tools.Where(t => t.Enabled == true).ToList();

            var settings = new Dictionary <string, object>
            {
                { "current", AccordionToolNameToDirectoryName(_currentlyDisplayedBook.BookInfo.CurrentTool) }
            };

            var decodableTool = tools.FirstOrDefault(t => t.Name == "decodableReader");

            if (decodableTool != null && !string.IsNullOrEmpty(decodableTool.State))
            {
                settings.Add("decodableState", decodableTool.State);
            }
            var leveledTool = tools.FirstOrDefault(t => t.Name == "leveledReader");

            if (leveledTool != null && !string.IsNullOrEmpty(leveledTool.State))
            {
                settings.Add("leveledState", leveledTool.State);
            }

            var settingsStr = JsonConvert.SerializeObject(settings);

            settingsStr = String.Format("function GetAccordionSettings() {{ return {0};}}", settingsStr) +
                          "\n$(document).ready(function() { restoreAccordionSettings(GetAccordionSettings()); });";

            var scriptElement = domForAccordion.RawDom.CreateElement("script");

            scriptElement.SetAttribute("type", "text/javascript");
            scriptElement.SetAttribute("id", "ui-accordionSettings");
            scriptElement.InnerText = settingsStr;

            domForAccordion.Head.InsertAfter(scriptElement, domForAccordion.Head.LastChild);

            // get additional tabs to load
            var checkedBoxes = new List <string>();

            if (tools.Any(t => t.Name == "decodableReader"))
            {
                AppendAccordionPanel(domForAccordion, FileLocator.GetFileDistributedWithApplication(Path.Combine(_accordionFolder, "DecodableRT", "DecodableRT.htm")));
                checkedBoxes.Add("showDRT");
            }

            if (tools.Any(t => t.Name == "leveledReader"))
            {
                AppendAccordionPanel(domForAccordion, FileLocator.GetFileDistributedWithApplication(Path.Combine(_accordionFolder, "LeveledRT", "LeveledRT.htm")));
                checkedBoxes.Add("showLRT");
            }

            // Load settings into the accordion panel
            AppendAccordionPanel(domForAccordion, FileLocator.GetFileDistributedWithApplication(Path.Combine(_accordionFolder, "settings", "Settings.htm")));

            // check the appropriate boxes
            foreach (var checkBoxId in checkedBoxes)
            {
                domForAccordion.Body.SelectSingleNode("//div[@id='" + checkBoxId + "']").InnerXml = "&#10004;";
            }

            XmlHtmlConverter.MakeXmlishTagsSafeForInterpretationAsHtml(domForAccordion.RawDom);
            return(TempFileUtils.CreateHtml5StringFromXml(domForAccordion.RawDom));
        }