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));
            }
        }
Exemplo n.º 2
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));
        }
Exemplo n.º 3
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));
        }
Exemplo n.º 4
0
 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)));
        }
Exemplo n.º 6
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
            });
        }
Exemplo n.º 7
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
            });
        }
Exemplo n.º 8
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));
        }