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; }
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); }
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); }
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); }
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 }
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. } } } }
public void SetLayout(Layout layout) { SizeAndOrientation.AddClassesForLayout(OurHtmlDom, layout); }
/// <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); } } }
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; }
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); } } } }
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); }
// 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); } } }
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); }
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; }
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); }
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); } }
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; }