//while in Bloom, we could have and edit style sheet or (someday) other modes. But when stored, //we want to make sure it's ready to be opened in a browser. private void MakeCssLinksAppropriateForStoredFile(HtmlDom dom) { dom.RemoveModeStyleSheets(); dom.AddStyleSheet("previewMode.css"); dom.AddStyleSheet("basePage.css"); EnsureHasLinksToStylesheets(dom); dom.SortStyleSheetLinks(); dom.RemoveFileProtocolFromStyleSheetLinks(); }
public void SortStyleSheetLinks_LeavesOverridesAtEndAndSpecialFilesInMiddle() { var content = @"<html><head> <link rel='stylesheet' href='my special b.css' type='text/css' /> <link rel='stylesheet' href='Factory-Xmatter.css' type='text/css' /> <link rel='stylesheet' href='my special a.css' type='text/css' /> <link rel='stylesheet' href='../settingsCollectionStyles.css' type='text/css' /> <link rel='stylesheet' href='my special c.css' type='text/css' /> <link rel='stylesheet' href='Basic book.css' type='text/css' /> <link rel='stylesheet' href='../customCollectionStyles.css' type='text/css' /> <link rel='stylesheet' href='customBookStyles.css' type='text/css' /> <link rel='stylesheet' href='basePage.css' type='text/css' /> <link rel='stylesheet' href='languageDisplay.css' type='text/css' /> <link rel='stylesheet' href='../../editMode.css' type='text/css' /> </head></html>"; var bookdom = new HtmlDom(content); bookdom.SortStyleSheetLinks(); var dom = bookdom.RawDom; AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[1][@href='basePage.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[2][@href='../../editMode.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[3][@href='Basic book.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[4][@href='Factory-Xmatter.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[5][@href='my special a.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[6][@href='my special b.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[7][@href='my special c.css']", 1); //NB: I (JH) don't for sure know yet what the order of this should be. I think it should be last-ish. AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[8][@href='languageDisplay.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[9][@href='../settingsCollectionStyles.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[10][@href='../customCollectionStyles.css']", 1); AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//head/link[11][@href='customBookStyles.css']", 1); }
public void SortStyleSheetLinks_LeavesBasePageBeforePreviewMode() { var dom = new HtmlDom( @"<html><head> <link rel='stylesheet' href='../../previewMode.css' type='text/css' /> <link rel='stylesheet' href='basePage.css' type='text/css' /> </head></html>"); dom.SortStyleSheetLinks(); AssertThatXmlIn.Dom(dom.RawDom).HasSpecifiedNumberOfMatchesForXpath("//head/link[1][@href='basePage.css']", 1); AssertThatXmlIn.Dom(dom.RawDom).HasSpecifiedNumberOfMatchesForXpath("//head/link[2][@href='../../previewMode.css']", 1); }
private static void MakeCssLinksAppropriateForEpub(HtmlDom dom) { dom.RemoveModeStyleSheets(); dom.SortStyleSheetLinks(); dom.RemoveFileProtocolFromStyleSheetLinks(); dom.RemoveDirectorySpecificationFromStyleSheetLinks(); }
//while in Bloom, we could have and edit style sheet or (someday) other modes. But when stored, //we want to make sure it's ready to be opened in a browser. private void MakeCssLinksAppropriateForStoredFile(HtmlDom dom) { dom.RemoveModeStyleSheets(); dom.AddStyleSheet("previewMode.css"); dom.AddStyleSheet("basePage.css"); EnsureHasLinksToStylesheets(dom); dom.SortStyleSheetLinks(); dom.RemoveFileProtocolFromStyleSheetLinks(); }
/// <summary> /// used when this book is a "master"/"folio" book that is used to bring together a number of other books in the collection /// </summary> /// <param name="printingDom"></param> /// <param name="currentBookCollection"></param> /// <param name="bookServer"></param> private void AddChildBookContentsToFolio(HtmlDom printingDom, BookCollection currentBookCollection, BookServer bookServer) { XmlNode currentLastContentPage = GetLastPageForInsertingNewContent(printingDom); //currently we have no way of filtering them, we just take them all foreach (var bookInfo in currentBookCollection.GetBookInfos()) { if (bookInfo.IsFolio) continue; var childBook =bookServer.GetBookFromBookInfo(bookInfo); //this will set the class bloom-content1 on the correct language //this happens anyhow if the page was ever looked at in the Edti Tab //But if we are testing a collection's folio pdf'ing ability on a newly-generated //SHRP collection, and we don't do this, we see lots of sample text because every //bloom-editable has "bloom-content1", even the "Z" language ones. childBook.UpdateEditableAreasOfElement(childBook.OurHtmlDom); //add links to the template css needed by the children. HtmlDom.AddStylesheetFromAnotherBook(childBook.OurHtmlDom, printingDom); printingDom.SortStyleSheetLinks(); foreach (XmlElement pageDiv in childBook.OurHtmlDom.RawDom.SafeSelectNodes("/html/body//div[contains(@class, 'bloom-page') and not(contains(@class,'bloom-frontMatter')) and not(contains(@class,'bloom-backMatter'))]")) { XmlElement importedPage = (XmlElement) printingDom.RawDom.ImportNode(pageDiv, true); currentLastContentPage.ParentNode.InsertAfter(importedPage, currentLastContentPage); currentLastContentPage = importedPage; foreach(XmlElement img in HtmlDom.SelectChildImgAndBackgroundImageElements(importedPage)) { var bookFolderName = Path.GetFileName(bookInfo.FolderPath); var path = HtmlDom.GetImageElementUrl(img); var pathRelativeToFolioFolder = ".../" + bookFolderName + "/" + path.NotEncoded; //NB: URLEncode would replace spaces with '+', which is ok in the parameter section, but not the URL //So we are using UrlPathEncode HtmlDom.SetImageElementUrl(new ElementProxy(img), UrlPathString.CreateFromUnencodedString(pathRelativeToFolioFolder)); } } } }
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); }
/// <summary> /// used when this book is a "master"/"folio" book that is used to bring together a number of other books in the collection /// </summary> /// <param name="printingDom"></param> /// <param name="currentBookCollection"></param> /// <param name="bookServer"></param> private void AddChildBookContentsToFolio(HtmlDom printingDom, BookCollection currentBookCollection, BookServer bookServer) { XmlNode currentLastContentPage = GetLastPageForInsertingNewContent(printingDom); //currently we have no way of filtering them, we just take them all foreach (var bookInfo in currentBookCollection.GetBookInfos()) { if (bookInfo.IsFolio) continue; var childBook =bookServer.GetBookFromBookInfo(bookInfo); //add links to the template css needed by the children. //NB: at this point this code can't hand the "customBookStyles" from children, it'll ignore them (they woul conflict with each other) //NB: at this point custom styles (e.g. larger/smaller font rules) from children will be lost. var customStyleSheets = new List<string>(); foreach (string sheetName in childBook.OurHtmlDom.GetTemplateStyleSheets()) { if (!customStyleSheets.Contains(sheetName)) //nb: if two books have stylesheets with the same name, we'll only be grabbing the 1st one. { customStyleSheets.Add(sheetName); printingDom.AddStyleSheetIfMissing("file://"+Path.Combine(childBook.FolderPath,sheetName)); } } printingDom.SortStyleSheetLinks(); foreach (XmlElement pageDiv in childBook.OurHtmlDom.RawDom.SafeSelectNodes("/html/body/div[contains(@class, 'bloom-page') and not(contains(@class,'bloom-frontMatter')) and not(contains(@class,'bloom-backMatter'))]")) { XmlElement importedPage = (XmlElement) printingDom.RawDom.ImportNode(pageDiv, true); currentLastContentPage.ParentNode.InsertAfter(importedPage, currentLastContentPage); currentLastContentPage = importedPage; ImageUpdater.MakeImagePathsOfImportedPagePointToOriginalLocations(importedPage, bookInfo.FolderPath); } } }