/// <summary> /// Adds reference /// Used to add hyperlinks (anchors) from one part of the document to another /// </summary> /// <param name="reference">reference name (name of the link we going to "jump to" - href)</param> /// <param name="anchor">anchor element that contains the reference (place we "jump from")</param> public void AddReference(string reference, Anchor anchor) { if (!ReferencesUtils.IsExternalLink(reference)) // we count only "internal" references (no need for http://... ) { reference = EnsureGoodReference(reference); // make sure that reference name is valid according to HTML rules List <Anchor> list; if (!_references.ContainsKey(reference)) // if this a first time we see "jump" to this ID { list = new List <Anchor>(); //allocate new list of referenced objects _references.Add(reference, list); // add list to dictionary } else // if we already have at least one reference to this ID { list = _references[reference]; // find this ID in references dictionary } if (string.IsNullOrEmpty((string)anchor.GlobalAttributes.ID.Value)) // if anchor does not have ID already (FB2 link element does not have ID so this is just in case), we need this for backlinking { string backLink = string.Format("{0}_back", reference); // generate back link if (backLink.StartsWith("#")) // most references starts with # as part of the href linking, so we need to strip this character to get valid ID { backLink = backLink.Substring(1); } while (IsIdUsed(backLink)) { backLink += "x"; } anchor.GlobalAttributes.ID.Value = backLink; } anchor.GlobalAttributes.ID.Value = AddIdUsed((string)anchor.GlobalAttributes.ID.Value, anchor); list.Add(anchor); } }
public void RemapAnchors(BookStructureManager structureManager) { var listToRemove = new List <string>(); foreach (var link in _references) { if (!ReferencesUtils.IsExternalLink(link.Key)) { if (IsIdUsed(link.Key)) { RemapInternalLink(structureManager, link); } else { listToRemove.Add(link.Key); RemoveInvalidAnchor(link); } } } // Remove the unused anchor (and their ID if they have one) // from the lists foreach (var toRemove in listToRemove) { _references.Remove(toRemove); } }
public void RemapAnchors(EPubFileV2 epubFile) { foreach (var link in _references) { if (!ReferencesUtils.IsExternalLink(link.Key)) { string idString = ReferencesUtils.GetIdFromLink(link.Key); BaseXHTMLFileV2 iDDocument = GetIDParentDocument(epubFile, _ids[idString]); if (iDDocument != null) { int count = 0; foreach (var anchor in link.Value) { BaseXHTMLFileV2 idDocument = GetIDParentDocument(epubFile, anchor); var referencedItem = _ids[(string)anchor.HRef.Value]; var newParent = DetectParentContainer(referencedItem); if (newParent == null) { continue; } var newAnchor = new Anchor(newParent.HTMLStandard); if (idDocument == iDDocument) { anchor.HRef.Value = string.Format("#{0}", idString); newAnchor.HRef.Value = string.Format("#{0}", anchor.GlobalAttributes.ID.Value); } else { anchor.HRef.Value = string.Format("{0}#{1}", iDDocument.FileName, idString); if (idDocument == null) { continue; } newAnchor.HRef.Value = string.Format("{0}#{1}", idDocument.FileName, anchor.GlobalAttributes.ID.Value); } if (iDDocument.Type == SectionTypeEnum.Links) // if it's FBE notes section { newAnchor.GlobalAttributes.Class.Value = ElementStylesV2.NoteAnchor; newParent.Add(new EmptyLine(newParent.HTMLStandard)); newParent.Add(newAnchor); count++; newAnchor.Add(new SimpleHTML5Text(newAnchor.HTMLStandard) { Text = (link.Value.Count > 1) ? string.Format("(<< back {0}) ", count) : string.Format("(<< back) ") }); } } } else { //throw new Exception("Internal consistency error - Used ID has to be in one of the book documents objects"); Logger.Log.Error("Internal consistency error - Used ID has to be in one of the book documents objects"); //continue; } } } }
/// <summary> /// Convert FB2 internal link /// </summary> /// <param name="internalLinkItem">item to convert</param> /// <param name="internalLinkConverterParams"></param> /// <returns>XHTML representation</returns> public List <IHTMLItem> Convert(InternalLinkItem internalLinkItem, InternalLinkConverterParamsV3 internalLinkConverterParams) { if (internalLinkItem == null) { throw new ArgumentNullException("internalLinkItem"); } var list = new List <IHTMLItem>(); if (!string.IsNullOrEmpty(internalLinkItem.HRef) && internalLinkItem.HRef != "#") { var anchor = new Anchor(HTMLElementType.HTML5); bool internalLink = false; if (!ReferencesUtils.IsExternalLink(internalLinkItem.HRef)) { if (internalLinkItem.HRef.StartsWith("#")) { internalLinkItem.HRef = internalLinkItem.HRef.Substring(1); } internalLinkItem.HRef = internalLinkConverterParams.Settings.ReferencesManager.EnsureGoodId(internalLinkItem.HRef); internalLink = true; } anchor.HRef.Value = internalLinkItem.HRef; if (internalLink) { internalLinkConverterParams.Settings.ReferencesManager.AddReference(internalLinkItem.HRef, anchor); } if (internalLinkItem.LinkText != null) { var tempConverter = new SimpleTextElementConverterV3(); foreach (var s in tempConverter.Convert(internalLinkItem.LinkText, new SimpleTextElementConverterParamsV3 { Settings = internalLinkConverterParams.Settings, NeedToInsertDrop = internalLinkConverterParams.NeedToInsertDrop } )) { s.Parent = anchor; anchor.Add(s); } } list.Add(anchor); return(list); } var converter = new SimpleTextElementConverterV3(); return(converter.Convert(internalLinkItem.LinkText, new SimpleTextElementConverterParamsV3 { Settings = internalLinkConverterParams.Settings, NeedToInsertDrop = internalLinkConverterParams.NeedToInsertDrop })); }
/// <summary> /// Processes all the references and removes invalid anchors /// Invalid meaning pointing to non-existing IDs /// only "internal" anchors are removed /// </summary> public void RemoveInvalidAnchors() { var listToRemove = new List <string>(); foreach (var reference in _references) { // If reference does not points on one of valid IDs and it's not external reference if (!IsIdUsed(reference.Key) && !ReferencesUtils.IsExternalLink(reference.Key)) { listToRemove.Add(reference.Key); // remove all references to this ID foreach (var element in _references[reference.Key]) { // The Anchor element can't have empty reference so // we remove it and in case it has some meaningful content // replace with span that is meaningless non-block element // so contained text etc are kept if (element.SubElements().Count != 0) { var spanElement = new Span(element.HTMLStandard); foreach (var subElement in element.SubElements()) { spanElement.Add(subElement); } if (element.Parent != null) { int index = element.Parent.SubElements().IndexOf(element); if (index != -1) { spanElement.Parent = element.Parent; element.Parent.SubElements().Insert(index, spanElement); } } if (!string.IsNullOrEmpty((string)element.GlobalAttributes.ID.Value)) { spanElement.GlobalAttributes.ID.Value = element.GlobalAttributes.ID.Value; // Copy ID anyway - may be someone "jumps" here _ids[(string)element.GlobalAttributes.ID.Value] = spanElement; // and update the "pointer" to element } spanElement.GlobalAttributes.Class.Value = ElementStylesV3.BadExternalLink; } if (element.Parent != null) { element.Parent.Remove(element); } } } } // Remove the unused anchor (and their ID if they have one) // from the lists foreach (var toRemove in listToRemove) { _references.Remove(toRemove); } }
public void AddBackReference(string reference, Anchor anchor) { if (!ReferencesUtils.IsExternalLink(reference)) // we count only "internal" references (no need for http://... ) { reference = EnsureGoodReference(reference); // make sure that reference name is valid according to HTML rules List <Anchor> list; if (!_references.ContainsKey(reference)) // if this a first time we see "jump" to this ID { list = new List <Anchor>(); //allocate new list of referenced objects _references.Add(reference, list); // add list to dictionary } else // if we already have at least one reference to this ID { list = _references[reference]; // find this ID in references dictionarry } list.Add(anchor); } }
public HTMLItem Convert(FB2File fb2File, ConverterOptionsV3 settings) { if (fb2File == null) { throw new ArgumentNullException("fb2File"); } var info = new Div(HTMLElementType.HTML5); var header = new H3(HTMLElementType.HTML5); header.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = "FB2 document info" }); info.Add(header); if (fb2File.DocumentInfo != null) { if (!string.IsNullOrEmpty(fb2File.DocumentInfo.ID)) { var p = new Paragraph(HTMLElementType.HTML5); p.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = string.Format("Document ID: {0}", fb2File.DocumentInfo.ID) }); info.Add(p); } if (fb2File.DocumentInfo.DocumentVersion.HasValue) { var p = new Paragraph(HTMLElementType.HTML5); p.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = string.Format("Document version: {0}", fb2File.DocumentInfo.DocumentVersion) }); info.Add(p); } if ((fb2File.DocumentInfo.DocumentDate != null) && !string.IsNullOrEmpty(fb2File.DocumentInfo.DocumentDate.Text)) { var p = new Paragraph(HTMLElementType.HTML5); p.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = string.Format("Document creation date: {0}", fb2File.DocumentInfo.DocumentDate.Text) }); info.Add(p); } if ((fb2File.DocumentInfo.ProgramUsed2Create != null) && !string.IsNullOrEmpty(fb2File.DocumentInfo.ProgramUsed2Create.Text)) { var p = new Paragraph(HTMLElementType.HTML5); p.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = string.Format("Created using: {0} software", fb2File.DocumentInfo.ProgramUsed2Create.Text) }); info.Add(p); } if ((fb2File.DocumentInfo.SourceOCR != null) && !string.IsNullOrEmpty(fb2File.DocumentInfo.SourceOCR.Text)) { var p = new Paragraph(HTMLElementType.HTML5); p.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = string.Format("OCR Source: {0}", fb2File.DocumentInfo.SourceOCR.Text) }); info.Add(p); } if ((fb2File.DocumentInfo.DocumentAuthors != null) && (fb2File.DocumentInfo.DocumentAuthors.Count > 0)) { var heading = new H4(HTMLElementType.HTML5); heading.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = "Document authors :" }); info.Add(heading); var authors = new UnorderedList(HTMLElementType.HTML5); foreach (var author in fb2File.DocumentInfo.DocumentAuthors) { var li = new ListItem(HTMLElementType.HTML5); li.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = DescriptionConverters.GetAuthorAsSting(author) }); authors.Add(li); } info.Add(authors); } if ((fb2File.DocumentInfo.DocumentPublishers != null) && (fb2File.DocumentInfo.DocumentPublishers.Count > 0)) { var heading = new H4(HTMLElementType.HTML5); heading.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = "Document publishers :" }); info.Add(heading); var publishers = new UnorderedList(HTMLElementType.HTML5); foreach (var publisher in fb2File.DocumentInfo.DocumentPublishers) { var li = new ListItem(HTMLElementType.HTML5); li.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = DescriptionConverters.GetAuthorAsSting(publisher) }); publishers.Add(li); } info.Add(publishers); } if ((fb2File.DocumentInfo.SourceURLs != null) && (fb2File.DocumentInfo.SourceURLs.Any())) { var heading = new H4(HTMLElementType.HTML5); heading.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = "Source URLs :" }); info.Add(heading); var urls = new UnorderedList(HTMLElementType.HTML5); foreach (var url in fb2File.DocumentInfo.SourceURLs) { var li = new ListItem(HTMLElementType.HTML5); if (ReferencesUtils.IsExternalLink(url)) { var link = new Anchor(HTMLElementType.HTML5); link.HRef.Value = url; link.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = url }); li.Add(link); } else { li.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = url }); } urls.Add(li); } info.Add(urls); } if (fb2File.DocumentInfo.History != null) { var heading = new H4(HTMLElementType.HTML5); heading.Add(new SimpleHTML5Text(HTMLElementType.HTML5) { Text = "Document history:" }); info.Add(heading); var annotationConverter = new AnnotationConverterV3(); info.Add(annotationConverter.Convert(fb2File.DocumentInfo.History, new AnnotationConverterParamsV3 { Level = 1, Settings = settings })); //Paragraph p = new Paragraph(); //p.Add(new SimpleHTML5Text() { Text = fb2File.DocumentInfo.History.ToString() }); //info.Add(p); } } // in case there is no elements - no need for a header if (info.SubElements().Count <= 1) { info.Remove(header); } SetClassType(info, ElementStylesV3.FB2Info); return(info); }