A Layout is size and orientation, plus options. Currently, there is only one set of options allowed, named "styles"
        public static int Handle(HydrateParameters options)
        {
            if (!Directory.Exists(options.Path))
            {
                if (options.Path.Contains(".htm"))
                {
                    Debug.WriteLine("Supply only the directory, not the path to the file.");
                    Console.Error.WriteLine("Supply only the directory, not the path to the file.");
                }
                else
                {
                    Debug.WriteLine("Could not find " + options.Path);
                    Console.Error.WriteLine("Could not find " + options.Path);
                }
                return 1;
            }
            Console.WriteLine("Starting Hydrating.");

            var layout = new Layout
            {
                SizeAndOrientation = SizeAndOrientation.FromString(options.SizeAndOrientation)
            };

            var collectionSettings = new CollectionSettings
            {
                XMatterPackName = "Video",
                Language1Iso639Code = options.VernacularIsoCode,
                Language2Iso639Code = options.NationalLanguage1IsoCode,
                Language3Iso639Code = options.NationalLanguage2IsoCode
            };

            XMatterPackFinder xmatterFinder = new XMatterPackFinder(new[] { BloomFileLocator.GetInstalledXMatterDirectory() });
            var locator = new BloomFileLocator(collectionSettings, xmatterFinder, ProjectContext.GetFactoryFileLocations(),
                ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());

            var bookInfo = new BookInfo(options.Path, true);
            var book = new Book.Book(bookInfo, new BookStorage(options.Path, locator, new BookRenamedEvent(), collectionSettings),
                null, collectionSettings, null, null, new BookRefreshEvent());

            if (null == book.OurHtmlDom.SelectSingleNodeHonoringDefaultNS("//script[contains(text(),'bloomPlayer.js')]"))
            {
                var element = book.OurHtmlDom.Head.AppendChild(book.OurHtmlDom.RawDom.CreateElement("script")) as XmlElement;
                element.IsEmpty = false;
                element.SetAttribute("type", "text/javascript");
                element.SetAttribute("src", "bloomPlayer.js");
            }

            AddRequisiteJsFiles(options.Path);

            //we might change this later, or make it optional, but for now, this will prevent surprises to processes
            //running this CLI... the folder name won't change out from under it.
            book.LockDownTheFileAndFolderName = true;

            book.SetLayout(layout);
            book.BringBookUpToDate(new NullProgress());
            Console.WriteLine("Finished Hydrating.");
            Debug.WriteLine("Finished Hydrating.");
            return 0;
        }
Example #2
0
        public void UpdatePageSplitMode_WasCombined_IndividualPagesHaveOwnIds()
        {
            var dom = new XmlDocument();
            dom.LoadXml(@"<html ><body><div id='foo'></div><div id='1' class='bloom-page A5Landscape bloom-combinedPage'></div></body></html>");
            var layout = new Layout() { ElementDistribution = Layout.ElementDistributionChoices.SplitAcrossPages };
            layout.UpdatePageSplitMode(dom);

            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[@id=1]", 0);
        }
Example #3
0
        public void UpdatePageSplitMode_WasCombined_IsNowSplitIntoTwoPages()
        {
            var dom = new XmlDocument();
            dom.LoadXml(@"<html ><body><div id='somemarginbox'><div class='bloom-page A5Landscape bloom-combinedPage'></div></div></body></html>");
            var layout = new Layout() {ElementDistribution = Layout.ElementDistributionChoices.SplitAcrossPages};
            layout.UpdatePageSplitMode(dom);

            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-page')]", 2);
            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-combinedPage')]", 0);
            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-leadingPage')]", 1);
            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-trailingPage')]", 1);
        }
Example #4
0
        public void UpdatePageSplitMode_WasCombinedAndShouldStayThatWay_PageUntouched()
        {
            var dom = new XmlDocument();
            dom.LoadXml(@"<html ><body><div id='foo'></div><div class='bloom-page A5Landscape bloom-combinedPage'></div></body></html>");
            var layout = new Layout() { ElementDistribution = Layout.ElementDistributionChoices.CombinedPages };
            layout.UpdatePageSplitMode(dom);

            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-page')]", 1);
            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-combinedPage')]", 1);
            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-leadingPage')]", 0);
            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//div[contains(@class,'bloom-trailingPage')]", 0);
        }
Example #5
0
        public void SetLayout(Layout layout)
        {
            SaveNow();
            CurrentBook.SetLayout(layout);
            CurrentBook.PrepareForEditing();
            _view.UpdateSingleDisplayedPage(_pageSelection.CurrentSelection);

            _view.UpdatePageList(true);//counting on this to redo the thumbnails
        }
Example #6
0
        public void InjectXMatter(Dictionary<string, string> writingSystemCodes, Layout layout)
        {
            //don't want to pollute shells with this content
            if (!string.IsNullOrEmpty(FolderPathForCopyingXMatterFiles))
            {
                //copy over any image files used by this front matter
                string path = Path.GetDirectoryName(PathToXMatterHtml);
                foreach (var file in Directory.GetFiles(path, "*.png").Concat(Directory.GetFiles(path, "*.jpg").Concat(Directory.GetFiles(path, "*.gif").Concat(Directory.GetFiles(path, "*.bmp")))))
                {
                    File.Copy(file, FolderPathForCopyingXMatterFiles.CombineForPath(Path.GetFileName(file)), true);
                }
            }

            //note: for debugging the template/css purposes, it makes our life easier if, at runtime, the html is pointing the original.
            //makes it easy to drop into a css editor and fix it up with the content we're looking at.
            //TODO:But then later, we want to save it so that these are found in the same dir as the book.
            _bookDom.AddStyleSheet(PathToStyleSheetForPaperAndOrientation);

            //it's important that we append *after* this, so that these values take precendance (the template will just have empty values for this stuff)
            //REVIEW: I think all stylesheets now get sorted once they are all added: see HtmlDoc.SortStyleSheetLinks()
            XmlNode divBeforeNextFrontMattterPage = _bookDom.RawDom.SelectSingleNode("//body/div[@id='bloomDataDiv']");

            foreach (XmlElement xmatterPage in XMatterDom.SafeSelectNodes("/html/body/div[contains(@data-page,'required')]"))
            {
                var newPageDiv = _bookDom.RawDom.ImportNode(xmatterPage, true) as XmlElement;
                //give a new id, else thumbnail caches get messed up becuase every book has, for example, the same id for the cover.
                newPageDiv.SetAttribute("id", Guid.NewGuid().ToString());

                if (IsBackMatterPage(xmatterPage))
                {
                    //note: this is redundant unless this is the 1st backmatterpage in the list
                    divBeforeNextFrontMattterPage = _bookDom.RawDom.SelectSingleNode("//body/div[last()]");
                }

                //we want the xmatter pages to match what we found in the source book
                SizeAndOrientation.UpdatePageSizeAndOrientationClasses(newPageDiv, layout);

                newPageDiv.InnerXml = newPageDiv.InnerXml.Replace("'V'", '"' + writingSystemCodes["V"] + '"');
                newPageDiv.InnerXml = newPageDiv.InnerXml.Replace("\"V\"", '"' + writingSystemCodes["V"] + '"');
                newPageDiv.InnerXml = newPageDiv.InnerXml.Replace("'N1'", '"' + writingSystemCodes["N1"] + '"');
                newPageDiv.InnerXml = newPageDiv.InnerXml.Replace("\"N1\"", '"' + writingSystemCodes["N1"] + '"');
                if (!String.IsNullOrEmpty(writingSystemCodes["N2"]))  //otherwise, styleshee will hide it
                {
                    newPageDiv.InnerXml = newPageDiv.InnerXml.Replace("'N2'", '"' + writingSystemCodes["N2"] + '"');
                    newPageDiv.InnerXml = newPageDiv.InnerXml.Replace("\"N2\"", '"' + writingSystemCodes["N2"] + '"');
                }

                _bookDom.RawDom.SelectSingleNode("//body").InsertAfter(newPageDiv, divBeforeNextFrontMattterPage);
                divBeforeNextFrontMattterPage = newPageDiv;

                //enhance... this is really ugly. I'm just trying to clear out any remaining "{blah}" left over from the template
                foreach (XmlElement e in newPageDiv.SafeSelectNodes("//*[starts-with(text(),'{')]"))
                {
                    foreach ( var node in e.ChildNodes)
                    {
                        XmlText t = node as XmlText;
                        if(t!=null && t.Value.StartsWith("{"))
                            t.Value =""; //otherwise html tidy will through away span's (at least) that are empty, so we never get a chance to fill in the values.
                    }
                }
            }
        }
Example #7
0
 public void SetLayout(Layout layout)
 {
     SizeAndOrientation.AddClassesForLayout(OurHtmlDom, layout);
 }
Example #8
0
        /// <summary>
        /// Some book layouts rely on the first page facing the second page. A Wall Calendar is one example.
        /// Here we check if the first content page has this requirement and, if so, we insert a blank "flyleaf"
        /// page.
        /// </summary>
        private void InjectFlyleafIfNeeded(Layout layout)
        {
            // the "inside" here means "not counting the cover"
            var numberOfFrontMatterPagesInside = XMatterDom.SafeSelectNodes("//div[contains(@class,'bloom-frontMatter')]").Count - 1;
            var firstPageWouldNotBePartOfASpread = numberOfFrontMatterPagesInside%2 != 0;

            if(firstPageWouldNotBePartOfASpread)
            {
                var lastFrontMatterPage = _bookDom.SelectSingleNode("//div[contains(@class,'bloom-frontMatter')][last()]");

                var firstContentPageAndAlsoStartsSpread = _bookDom.SelectSingleNode(
                    "//div[contains(@class,'bloom-frontMatter')][last()]" // last frontmatter page
                    + "/following-sibling::div[contains(@data-page, 'spread-start')]");
                    // page after that says it needs to be facing the next page
                if(firstContentPageAndAlsoStartsSpread != null)
                {
                    var flyDom = new XmlDocument();
                    flyDom.LoadXml(@"
                        <div class='bloom-flyleaf bloom-frontMatter bloom-page' data-page='required singleton'>
                            <div class='pageLabel'>Flyleaf</div>
                            <div style='height: 100px; width:100%'
                                data-hint='This page was automatically inserted because the following page is marked as part of a two page spread.'>
                            </div>
                        </div>");
                    var flyleaf = _bookDom.RawDom.ImportNode(flyDom.FirstChild, true) as XmlElement;
                    flyleaf.SetAttribute("id", Guid.NewGuid().ToString());
                    lastFrontMatterPage.ParentNode.InsertAfter(flyleaf, lastFrontMatterPage);
                    SizeAndOrientation.UpdatePageSizeAndOrientationClasses(flyleaf, layout);
                }
            }
        }
Example #9
0
 private static Layout EnsureLayoutIsAmongValidChoices(HtmlDom dom, Layout layout, IFileLocator fileLocator)
 {
     var layoutChoices = SizeAndOrientation.GetLayoutChoices(dom, fileLocator);
     if (layoutChoices.Any(l => l.SizeAndOrientation.ClassName == layout.SizeAndOrientation.ClassName))
         return layout;
     return layoutChoices.Any() ?  layoutChoices.First() : layout;
 }
Example #10
0
        private void CleanupBrandingImages(XmlElement newPageDiv, string branding, string bookFolderPath, Layout layout)
        {
            if (branding == null)
            {
                return;                 // in testing.
            }
            if (BookStorage.IsStaticContent(bookFolderPath))
            {
                return;
            }
            var prefix = BrandingApi.kApiBrandingImage + "?id=";

            foreach (XmlElement imageElt in newPageDiv.SafeSelectNodes("//img").Cast <XmlElement>().ToArray())
            {
                var src = imageElt.Attributes["src"]?.Value;
                if (src == null || !src.StartsWith(prefix))
                {
                    continue;
                }
                var fileName        = src.Substring(prefix.Length);
                var pathToRealImage = BrandingApi.FindBrandingImageFileIfPossible(branding, fileName, layout);
                if (string.IsNullOrEmpty(pathToRealImage))
                {
                    if (!TemporaryDom)
                    {
                        // If the book folder contains this file already, it's obsolete, from some previous branding choice.
                        // Get rid of it to save space. We might also have an obsolete file with a png extension; get rid of
                        // that too. Of course, if this is just for a temporary DOM, we don't want to mess with the real folder.
                        var destFileName = Path.Combine(bookFolderPath, fileName);
                        RobustFile.Delete(destFileName);
                        RobustFile.Delete(Path.ChangeExtension(destFileName, ".png"));
                    }
                    // At this point the <img> element has src api/branding/something not in the current branding.
                    // So it's not actually going to produce an image in Bloom itself. We could change it, as
                    // in the following block, so that it points to a non-existent file in the book folder,
                    // and do various tricks to try to prevent warnings about missing files.
                    // But such an element does no good. Even if someone manually inserted the missing file
                    // (presumably an attempt to circumvent the current branding?) the next bring-book-up-to-date
                    // will remove it as not part of the current branding.
                    // Meanwhile, we need tricks to prevent missing-image errors in Bloom itself, and more tricks
                    // to prevent them in epubs, and .bloomd, and however else we might publish.
                    // All this is made unnecessary by just deleting the <img> element if it's not used in the
                    // current branding.
                    // If we later switch to a different branding which does need it,
                    // the next cycle of updating xmatter will start again with the original xmatter files
                    // which contain all the api/branding urls, and this time we will find the file and not
                    // delete the <img>.
                    imageElt.ParentNode.RemoveChild(imageElt);
                }
                else
                {
                    if (TemporaryDom)
                    {
                        // for a temporary DOM we don't care if the path is absolute and to something outside the book folder.
                        // It just has to work. And we don't want to modify the book folder. It does need to go through the
                        // image server, otherwise we'll get cross-domain problems. And we need the marker that prevents
                        // creating screen-only quality images.
                        imageElt.SetAttribute("src", (EnhancedImageServer.OriginalImageMarker + "/" + pathToRealImage).ToLocalhost());
                    }
                    else
                    {
                        // We want to actually copy it into the book folder, where things will work right
                        // even if someone just opens the HTML file in a context where our image server isn't
                        // running at all.
                        // We want to use the original name in the book folder...for one thing, works with
                        // deletion code above...but the correct extension for the file we actually found.
                        var destFileName = Path.ChangeExtension(Path.GetFileName(fileName), Path.GetExtension(pathToRealImage));
                        RobustFile.Copy(pathToRealImage, Path.Combine(bookFolderPath, destFileName), true);
                        // Point the <img> element at the local file...which should be available since we
                        // just copied it there.
                        imageElt.SetAttribute("src", destFileName);
                    }
                }
            }
        }
Example #11
0
        public void InjectXMatter(Dictionary <string, string> writingSystemCodes, Layout layout, string branding, string bookFolderPath)
        {
            //don't want to pollute shells with this content
            if (!string.IsNullOrEmpty(FolderPathForCopyingXMatterFiles))
            {
                //copy over any image files used by this front matter
                string path = Path.GetDirectoryName(PathToXMatterHtml);
                foreach (var file in Directory.GetFiles(path, "*.png").Concat(Directory.GetFiles(path, "*.jpg").Concat(Directory.GetFiles(path, "*.gif").Concat(Directory.GetFiles(path, "*.bmp")))))
                {
                    RobustFile.Copy(file, FolderPathForCopyingXMatterFiles.CombineForPath(Path.GetFileName(file)), true);
                }
            }

            //note: for debugging the template/css purposes, it makes our life easier if, at runtime, the html is pointing the original.
            //makes it easy to drop into a css editor and fix it up with the content we're looking at.
            //TODO:But then later, we want to save it so that these are found in the same dir as the book.
            _bookDom.AddStyleSheet(PathToXMatterStylesheet.ToLocalhost());

            //it's important that we append *after* this, so that these values take precendance (the template will just have empty values for this stuff)
            //REVIEW: I think all stylesheets now get sorted once they are all added: see HtmlDoc.SortStyleSheetLinks()
            XmlNode divBeforeNextFrontMattterPage = _bookDom.RawDom.SelectSingleNode("//body/div[@id='bloomDataDiv']");

            foreach (XmlElement xmatterPage in XMatterDom.SafeSelectNodes("/html/body/div[contains(@data-page,'required')]"))
            {
                var newPageDiv = _bookDom.RawDom.ImportNode(xmatterPage, true) as XmlElement;
                //give a new id, else thumbnail caches get messed up becuase every book has, for example, the same id for the cover.
                newPageDiv.SetAttribute("id", Guid.NewGuid().ToString());

                CleanupBrandingImages(newPageDiv, branding, bookFolderPath, layout);

                if (IsBackMatterPage(xmatterPage))
                {
                    //note: this is redundant unless this is the 1st backmatterpage in the list
                    divBeforeNextFrontMattterPage = _bookDom.RawDom.SelectSingleNode("//body/div[last()]");
                }

                //we want the xmatter pages to match what we found in the source book
                SizeAndOrientation.UpdatePageSizeAndOrientationClasses(newPageDiv, layout);

                //any @lang attributes that have a metalanguage code (N1, N2, V) get filled with the actual code.
                //note that this older method is crude, as you're in trouble if the user changes one of those to
                //a different language. Instead, use data-metalanguage.
                foreach (XmlElement node in newPageDiv.SafeSelectNodes("//*[@lang]"))
                {
                    var lang = node.GetAttribute("lang");
                    if (writingSystemCodes.ContainsKey(lang))
                    {
                        node.SetAttribute("lang", writingSystemCodes[lang]);
                    }
                }

                _bookDom.RawDom.SelectSingleNode("//body").InsertAfter(newPageDiv, divBeforeNextFrontMattterPage);
                divBeforeNextFrontMattterPage = newPageDiv;

                //enhance... this is really ugly. I'm just trying to clear out any remaining "{blah}" left over from the template
                foreach (XmlElement e in newPageDiv.SafeSelectNodes("//*[starts-with(text(),'{')]"))
                {
                    foreach (var node in e.ChildNodes)
                    {
                        XmlText t = node as XmlText;
                        if (t != null && t.Value.StartsWith("{"))
                        {
                            t.Value = "";                            //otherwise html tidy will through away span's (at least) that are empty, so we never get a chance to fill in the values.
                        }
                    }
                }
            }
            InjectFlyleafIfNeeded(layout);
        }
Example #12
0
 // for testing. Real code should supply the bookFolderPath argument.
 internal void InjectXMatter(Dictionary <string, string> writingSystemCodes, Layout layout)
 {
     InjectXMatter(writingSystemCodes, layout, null, null);
 }
 public static void AddClassesForLayout(HtmlDom dom, Layout layout)
 {
     UpdatePageSizeAndOrientationClasses(dom.RawDom, layout);
 }
        public static void UpdatePageSizeAndOrientationClasses(XmlNode node, Layout layout)
        {
            foreach (XmlElement pageDiv in node.SafeSelectNodes("descendant-or-self::div[contains(@class,'bloom-page')]"))
            {
                RemoveClassesContaining(pageDiv, "layout-");
                RemoveClassesContaining(pageDiv, "Landscape");
                RemoveClassesContaining(pageDiv, "Portrait");

                foreach (var cssClassName in layout.ClassNames)
                {
                    AddClass(pageDiv, cssClassName);
                }
            }
        }
Example #15
0
        public void InjectXMatter(Dictionary <string, string> writingSystemCodes, Layout layout, bool orderXmatterForDeviceUse, string metadataIsoCode)
        {
            //don't want to pollute shells with this content
            if (!string.IsNullOrEmpty(FolderPathForCopyingXMatterFiles))
            {
                //copy over any image files used by this front matter
                string path = Path.GetDirectoryName(PathToXMatterHtml);
                foreach (var file in Directory.GetFiles(path, "*.png").Concat(Directory.GetFiles(path, "*.jpg").Concat(Directory.GetFiles(path, "*.gif").Concat(Directory.GetFiles(path, "*.bmp")))))
                {
                    string destFileName = FolderPathForCopyingXMatterFiles.CombineForPath(Path.GetFileName(file));
                    Utils.LongPathAware.ThrowIfExceedsMaxPath(destFileName);
                    RobustFile.Copy(file, destFileName, true);
                }
            }

            //note: for debugging the template/css purposes, it makes our life easier if, at runtime, the html is pointing the original.
            //makes it easy to drop into a css editor and fix it up with the content we're looking at.
            //TODO:But then later, we want to save it so that these are found in the same dir as the book.
            _bookDom.AddStyleSheet(PathToXMatterStylesheet.ToLocalhost());
            // Get the xMatter stylesheet link in the proper place rather than at the end.
            // See https://issues.bloomlibrary.org/youtrack/issue/BL-8845.
            _bookDom.SortStyleSheetLinks();

            //it's important that we append *after* this, so that these values take precedence (the template will just have empty values for this stuff)
            //REVIEW: I think all stylesheets now get sorted once they are all added: see HtmlDoc.SortStyleSheetLinks()
            XmlNode divBeforeNextFrontMatterPage = _bookDom.RawDom.SelectSingleNode("//body/div[@id='bloomDataDiv']");

            foreach (XmlElement xmatterPage in XMatterDom.SafeSelectNodes("/html/body/div[contains(@data-page,'required')]"))
            {
                var newPageDiv = _bookDom.RawDom.ImportNode(xmatterPage, true) as XmlElement;
                //give a new id, else thumbnail caches get messed up because every book has, for example, the same id for the cover.
                newPageDiv.SetAttribute("id", Guid.NewGuid().ToString());

                // Various fields don't have a useful lang attribute value (doesn't exist or is "*") but we need a lang attribute to set the font properly.
                // By setting it on the page, all those fields can properly inherit the language 2 code and thus use its font. See BL-8545.
                // Since we are only doing this for xmatter, we don't have to worry about the lang attribute staying around when it shouldn't.
                // Old Blooms will effectively remove it when injecting xmatter. New Blooms will always set it to the current language 2 code.
                newPageDiv.SetAttribute("lang", metadataIsoCode);

                // We have some xmatters that don't know about devices, and these we replace with the
                // standard Device Xmatter as needed.
                // There is a second type where we have explicitly made a special xmatter just for devices:
                // ABC, Dari, and Pasti are examples of these.
                // Finally, we have other xmatters that deal with device formatting via a stylesheet, without having
                // a second folder and html for devices (e.g. Kyrgyzstan 2020). For this last one, we want to
                // just automatically reorder the pages, when we are preparing the document for publishing
                // to device contexts.
                var moveNonCoverToBack = orderXmatterForDeviceUse && !PathToXMatterStylesheet.Contains("Device-XMatter");
                if (IsBackMatterPage(xmatterPage) || (moveNonCoverToBack && ShouldBeInBackForDeviceUse(xmatterPage)))
                {
                    //note: this is redundant unless this is the 1st backmatterpage in the list
                    divBeforeNextFrontMatterPage = _bookDom.RawDom.SelectSingleNode("//body/div[last()]");
                }

                //we want the xmatter pages to match what we found in the source book
                SizeAndOrientation.UpdatePageSizeAndOrientationClasses(newPageDiv, layout);

                //any @lang attributes that have a metalanguage code (N1, N2, V) get filled with the actual code.
                //note that this older method is crude, as you're in trouble if the user changes one of those to
                //a different language. Instead, use data-metalanguage.
                foreach (XmlElement node in newPageDiv.SafeSelectNodes("//*[@lang]"))
                {
                    var lang = node.GetAttribute("lang");
                    if (writingSystemCodes.ContainsKey(lang))
                    {
                        node.SetAttribute("lang", writingSystemCodes[lang]);
                    }
                }

                _bookDom.RawDom.SelectSingleNode("//body").InsertAfter(newPageDiv, divBeforeNextFrontMatterPage);
                divBeforeNextFrontMatterPage = newPageDiv;

                //enhance... this is really ugly. I'm just trying to clear out any remaining "{blah}" left over from the template
                foreach (XmlElement e in newPageDiv.SafeSelectNodes("//*[starts-with(text(),'{')]"))
                {
                    foreach (var node in e.ChildNodes)
                    {
                        XmlText t = node as XmlText;
                        if (t != null && t.Value.StartsWith("{"))
                        {
                            t.Value = "";                            //otherwise html tidy will through away span's (at least) that are empty, so we never get a chance to fill in the values.
                        }
                    }
                }
            }
            InjectFlyleafIfNeeded(layout);
        }
Example #16
0
        public static Layout FromDom(HtmlDom dom, Layout defaultIfMissing)
        {
            var firstPage = dom.SelectSingleNode("descendant-or-self::div[contains(@class,'bloom-page')]");
            if (firstPage == null)
                return defaultIfMissing;

            var layout = new Layout {SizeAndOrientation = defaultIfMissing.SizeAndOrientation, Style= defaultIfMissing.Style};

            foreach (var part in firstPage.GetStringAttribute("class").SplitTrimmed(' '))
            {
                if (part.ToLower().Contains("portrait") || part.ToLower().Contains("landscape"))
                {
                    layout.SizeAndOrientation = SizeAndOrientation.FromString(part);
                }
                if (part.ToLower().Contains("layout-style-"))
                {
                    int startIndex = "layout-style-".Length;
                    layout.Style = part.Substring(startIndex, part.Length-startIndex);	//reivew: this might let us suck up a style that is no longer listed in any css
                }
            }
            return layout;
        }
Example #17
0
        private string SetupNewDocumentContents(string sourceFolderPath, string initialPath)
        {
            var  storage        = _bookStorageFactory(initialPath);
            bool usingTemplate  = storage.BookInfo.IsSuitableForMakingShells;
            bool makingTemplate = storage.BookInfo.IsSuitableForMakingTemplates;
            // If we're not making it from a template or making a template, we're deriving a translation from an existing book
            var makingTranslation = !usingTemplate && !makingTemplate;

            var bookData = new BookData(storage.Dom, _collectionSettings, null);

            UpdateEditabilityMetadata(storage);            //Path.GetFileName(initialPath).ToLower().Contains("template"));
            // BL-7614 We don't want a derivative of a book downloaded from a "bookshelf" to have the same bookshelf
            storage.BookInfo.ClearBookshelf();

            // NB: For a new book based on a page template, I think this should remove *everything*,
            // because the rest is in the xmatter.
            // For shells, we'll still have pages.

            // BL-6108: But if this is a template and we remove all the pages and xmatter,
            // there won't be anything left to tell us what the template's preferred layout was,
            // so we'll save that first.
            Layout templateLayout = null;

            if (usingTemplate)
            {
                templateLayout = Layout.FromDom(storage.Dom, Layout.A5Portrait);
            }

            // Remove from the new book any pages labeled as "extra".
            // Typically pages in a template are marked "extra" to indicate that they are options to insert with "Add Page"
            // but not pages (which a few templates have) that should be automatically inserted into every book
            // made from the template.
            // Originally we removed 'extra' pages in all cases, but we haven't actually used the capability
            // of deleting 'extra' pages from translations of shell books, and on the other hand, we did briefly release
            // a version of Bloom that incorrectly left shell book pages so marked. Something like 73 books in our library
            // may have this problem (BL-6392). Since we don't actually need the capability for making translations
            // of shell books, we decided to simply disable it: all pages in a shell book, even those marked
            // 'extra', will be kept in the translation.
            if (!makingTranslation)
            {
                for (var initialPageDivs = storage.Dom.SafeSelectNodes("/html/body/div[contains(@data-page,'extra')]");
                     initialPageDivs.Count > 0;
                     initialPageDivs = storage.Dom.SafeSelectNodes("/html/body/div[contains(@data-page,'extra')]"))
                {
                    initialPageDivs[0].ParentNode.RemoveChild(initialPageDivs[0]);
                }
            }
            else
            {
                // When making a translation of an original move the 'publisher' (if there is one) to 'originalPublisher'.
                storage.BookInfo.MovePublisherToOriginalPublisher();
            }

            XMatterHelper.RemoveExistingXMatter(storage.Dom);

            // BL-4586 Some old books ended up with background-image urls containing XML img tags
            // in the HTML-encoded string. This happened because the coverImage data-book element
            // contained an img tag instead of a bare filename.
            // Normally such a thing would get fixed on loading the book, but if the "old book" in question
            // is a shell downloaded from BloomLibrary.org, Bloom is not allowed to modify the book,
            // so if such a thing exists in this copied book here we will strip it out and replace it with the
            // filename in the img src attribute.
            Book.RemoveImgTagInDataDiv(storage.Dom);

            bookData.RemoveAllForms("ISBN");            //ISBN number of the original doesn't apply to derivatives

            var sizeAndOrientation = Layout.FromDomAndChoices(storage.Dom, templateLayout ?? Layout.A5Portrait, _fileLocator);

            //Note that we do this *before* injecting frontmatter, which is more likely to have a good reason for having English
            //Useful for things like Primers. Note that Lorem Ipsum and prefixing all text with "_" also work.
            //			if ("true"==GetMetaValue(storage.Dom.RawDom, "removeTranslationsWhenMakingNewBook", "false"))
            //			{
            //				ClearAwayAllTranslations(storage.Dom.RawDom);
            //			}

            ProcessXMatterMetaTags(storage);
            // If we are making a shell (from a template, as opposed to making a translation of a shell),
            // it should not have a pre-determined license. A default will be filled in later.
            // (But, if we're MAKING a template, we want to keep the CC0 from Template Starter.)
            if (usingTemplate && !makingTemplate)
            {
                BookCopyrightAndLicense.RemoveLicense(storage);
            }

            InjectXMatter(initialPath, storage, sizeAndOrientation);

            SetLineageAndId(storage, sourceFolderPath);

            if (makingTranslation)
            {
                storage.EnsureOriginalTitle();                 // Before SetBookTitle, so we definitely won't use this book's new empty title
            }

            SetBookTitle(storage, bookData, usingTemplate);

            TransformCreditPageData(storage.Dom, bookData, _collectionSettings, storage, makingTranslation);

            //Few sources will have this set at all. A template picture dictionary is one place where we might expect it to call for, say, bilingual
            int multilingualLevel = int.Parse(GetMetaValue(storage.Dom.RawDom, "defaultMultilingualLevel", "1"));

            TranslationGroupManager.SetInitialMultilingualSetting(bookData, multilingualLevel);

            var sourceDom = XmlHtmlConverter.GetXmlDomFromHtmlFile(sourceFolderPath.CombineForPath(Path.GetFileName(GetPathToHtmlFile(sourceFolderPath))), false);

            //If this is a shell book, make elements to hold the vernacular
            foreach (XmlElement div in storage.Dom.RawDom.SafeSelectNodes("//div[contains(@class,'bloom-page')]"))
            {
                XmlElement sourceDiv = sourceDom.SelectSingleNode("//div[@id='" + div.GetAttribute("id") + "']") as XmlElement;
                SetupIdAndLineage(sourceDiv, div);
                SetupPage(div, bookData);
            }

            ClearAwayDraftText(storage.Dom.RawDom);

            storage.UpdateSupportFiles();                // Copy branding files etc.
            storage.PerformNecessaryMaintenanceOnBook(); // Fix image files as needed etc.

            try
            {
                storage.Save();
            }
            catch (UnauthorizedAccessException e)
            {
                BookStorage.ShowAccessDeniedErrorReport(e);
                // Well, not sure what else to return here, so I guess just let it continue and return storage.FolderPath
            }

            //REVIEW this actually undoes the setting of the initial files name:
            //      storage.UpdateBookFileAndFolderName(_librarySettings);
            return(storage.FolderPath);
        }
Example #18
0
        private void InjectXMatter(string initialPath, BookStorage storage, Layout sizeAndOrientation)
        {
            //now add in the xmatter from the currently selected xmatter pack
            if (!TestingSoSkipAddingXMatter)
            {
                var data = new DataSet();
                Debug.Assert(!string.IsNullOrEmpty(_collectionSettings.Language1Iso639Code));
                Debug.Assert(!string.IsNullOrEmpty(_collectionSettings.Language2Iso639Code));
                data.WritingSystemCodes.Add("V", _collectionSettings.Language1Iso639Code);
                data.WritingSystemCodes.Add("N1", _collectionSettings.Language2Iso639Code);
                data.WritingSystemCodes.Add("N2", _collectionSettings.Language3Iso639Code);

                //by default, this comes from the collection, but the book can select one, inlucing "null" to select the factory-supplied empty xmatter
                var xmatterName = storage.Dom.GetMetaValue("xmatter", _collectionSettings.XMatterPackName);

                var helper = new XMatterHelper(storage.Dom, xmatterName, _fileLocator);
                helper.FolderPathForCopyingXMatterFiles = storage.FolderPath;
                helper.InjectXMatter(data.WritingSystemCodes, sizeAndOrientation);
            }
        }
Example #19
0
 public static Layout FromDomAndChoices(HtmlDom dom, Layout defaultIfMissing, IFileLocator fileLocator)
 {
     // If the stylesheet's special style which tells us which page/orientations it supports matches the default
     // page size and orientation in the template's bloom-page class, we don't need this method.
     // Otherwise, we need to make sure that the book's layout updates to something that really is a possibility.
     var layout = FromDom(dom, defaultIfMissing);
     layout = EnsureLayoutIsAmongValidChoices(dom, layout, fileLocator);
     return layout;
 }