/// <summary>
        /// This is where all the excitement happens. We update the specified group
        /// with the data from the spreadsheet row.
        /// </summary>
        /// <param name="row"></param>
        /// <param name="group"></param>
        private void PutRowInGroup(ContentRow row, XmlElement group)
        {
            var sheetLanguages = _sheet.Languages;

            foreach (var lang in sheetLanguages)
            {
                var colIndex = _sheet.GetRequiredColumnForLang(lang);
                var content  = row.GetCell(colIndex).Content;
                var editable = HtmlDom.GetEditableChildInLang(group, lang);
                if (editable == null)
                {
                    if (IsEmptyCell(content))
                    {
                        continue;                         // Review: or make an empty one?
                    }
                    editable = TranslationGroupManager.MakeElementWithLanguageForOneGroup(group, lang);
                }

                if (IsEmptyCell(content))
                {
                    editable.ParentNode.RemoveChild(editable);
                }
                else
                {
                    editable.InnerXml = content;
                }
            }

            if (RemoveOtherLanguages)
            {
                HtmlDom.RemoveOtherLanguages(@group, sheetLanguages);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// This is where all the excitement happens. We update the specified group
        /// with the data from the spreadsheet row.
        /// </summary>
        /// <param name="row"></param>
        /// <param name="group"></param>
        private void PutRowInGroup(ContentRow row, XmlElement group)
        {
            var sheetLanguages = _sheet.Languages;

            foreach (var lang in sheetLanguages)
            {
                var colIndex = _sheet.ColumnForLang(lang);
                var content  = row.GetCell(colIndex).Content;
                var editable = HtmlDom.GetEditableChildInLang(group, lang);
                if (editable == null)
                {
                    if (string.IsNullOrEmpty(content))
                    {
                        continue;                                          // Review: or make an empty one?
                    }
                    var temp = HtmlDom.GetEditableChildInLang(group, "z"); // standard template element
                    if (temp == null)
                    {
                        temp = HtmlDom.GetEditableChildInLang(group, null);                         // use any available template
                    }
                    if (temp == null)
                    {
                        // Enhance: Eventually we should be able to come up with some sort of default here.
                        // Since this is a rather simple temporary expedient I haven't unit tested it.
                        _warnings.Add(
                            $"Could not import group {_groupOnPageIndex} ({content}) on page {HtmlDom.NumberOfPage(_currentPage)} because it has no bloom-editable children to use as templates.");
                        return;
                    }

                    editable = temp.Clone() as XmlElement;
                    editable.SetAttribute("lang", lang);
                    group.AppendChild(editable);
                }

                if (HasMarkup(content))
                {
                    try
                    {
                        editable.InnerXml = content;
                    }
                    catch (XmlException)
                    {
                        // It wasn't XML after all? Just somehow had a wedge? Keep the whole lot as text.
                        SetContentAsText(editable, content);
                    }
                }
                else
                {
                    SetContentAsText(editable, content);
                }
            }

            if (RemoveOtherLanguages)
            {
                HtmlDom.RemoveOtherLanguages(@group, sheetLanguages);
            }
        }
        private bool RowHasText(ContentRow row)
        {
            var sheetLanguages = _sheet.Languages;

            foreach (var lang in sheetLanguages)
            {
                var colIndex = _sheet.GetRequiredColumnForLang(lang);
                var content  = row.GetCell(colIndex).Content;
                if (!string.IsNullOrEmpty(content))
                {
                    return(true);
                }
            }
            return(false);
        }
        private void PutRowInImage(ContentRow currentRow)
        {
            var spreadsheetImgPath = currentRow.GetCell(InternalSpreadsheet.ImageSourceColumnLabel).Content;

            if (spreadsheetImgPath == InternalSpreadsheet.BlankContentIndicator)
            {
                spreadsheetImgPath = "placeHolder.png";
            }

            var destFileName = Path.GetFileName(spreadsheetImgPath);

            var imgElement = GetImgFromContainer(_currentImageContainer);

            // Enhance: warn if null?
            imgElement?.SetAttribute("src", UrlPathString.CreateFromUnencodedString(destFileName).UrlEncoded);
            // Earlier versions of Bloom often had explicit height and width settings on images.
            // In case anything of the sort remains, it probably won't be correct for the new image,
            // so best to get rid of it.
            imgElement?.RemoveAttribute("height");
            imgElement?.RemoveAttribute("width");
            // image containers often have a generated title attribute that gives the file name and
            // notes about its resolution, etc. We think it will be regenerated as needed, but certainly
            // the one from a previous image is no use.
            _currentImageContainer.RemoveAttribute("title");
            if (_pathToSpreadsheetFolder != null)             //currently will only be null in tests
            {
                // To my surprise, if spreadsheetImgPath is rooted (a full path), this will just use it,
                // ignoring _pathToSpreadsheetFolder, which is what we want.
                var fullSpreadsheetPath = Path.Combine(_pathToSpreadsheetFolder, spreadsheetImgPath);
                if (spreadsheetImgPath == "placeHolder.png")
                {
                    // Don't assume the source has it, let's get a copy from files shipped with Bloom
                    fullSpreadsheetPath = Path.Combine(BloomFileLocator.FactoryCollectionsDirectory, "template books",
                                                       "Basic Book", "placeHolder.png");
                }

                CopyImageFileToDestination(destFileName, fullSpreadsheetPath, imgElement);
            }
        }
        private void UpdateDataDivFromRow(ContentRow currentRow, string dataBookLabel)
        {
            if (dataBookLabel.Contains("branding"))
            {
                return;                 // branding data-div elements are complex and difficult and determined by current collection state
            }
            // Only a few of these are worth reporting
            string whatsUpdated = null;

            switch (dataBookLabel)
            {
            case "coverImage":
                whatsUpdated = "the image on the cover";
                break;

            case "bookTitle":
                whatsUpdated = "the book title";
                break;

            case "copyright":
                whatsUpdated = "copyright information";
                break;
            }
            if (whatsUpdated != null)
            {
                Progress($"Updating {whatsUpdated}.");
            }

            var        xPath         = "div[@data-book=\"" + dataBookLabel + "\"]";
            var        matchingNodes = _dataDivElement.SelectNodes(xPath);
            XmlElement templateNode;
            bool       templateNodeIsNew = false;

            if (matchingNodes.Count > 0)
            {
                templateNode = (XmlElement)matchingNodes[0];
            }
            else
            {
                templateNodeIsNew = true;
                templateNode      = _destinationDom.RawDom.CreateElement("div");
                templateNode.SetAttribute("data-book", dataBookLabel);
            }

            var  imageSrcCol   = _sheet.GetColumnForTag(InternalSpreadsheet.ImageSourceColumnLabel);
            var  imageSrc      = imageSrcCol >= 0 ? currentRow.GetCell(imageSrcCol).Content : null;       // includes "images" folder
            var  imageFileName = Path.GetFileName(imageSrc);
            bool specificLanguageContentFound = false;
            bool asteriskContentFound         = false;

            //Whether or not a data-book div has a src attribute, we found that the innerText is used to set the
            //src of the image in the actual pages of the document, though we haven't found a case where they differ.
            //So during export we put the innerText into the image source column, and want to put it into
            //both src and innertext on import, unless the element is in the noSrcAttribute list
            if (imageFileName.Length > 0)
            {
                templateNode.SetAttribute("lang", "*");
                templateNode.InnerText = imageFileName;

                if (!SpreadsheetExporter.DataDivImagesWithNoSrcAttributes.Contains(dataBookLabel))
                {
                    templateNode.SetAttribute("src", imageFileName);
                }
                if (templateNodeIsNew)
                {
                    AddDataBookNode(templateNode);
                }

                if (_pathToSpreadsheetFolder != null)
                {
                    // Make sure the image gets copied over too.
                    var fullSpreadsheetPath = Path.Combine(_pathToSpreadsheetFolder, imageSrc);
                    CopyImageFileToDestination(imageFileName, fullSpreadsheetPath);
                }
            }
            else             //This is not an image node
            {
                if (dataBookLabel.Equals("coverImage"))
                {
                    Warn("No cover image found");
                }

                foreach (string lang in _sheet.Languages)
                {
                    var langVal           = currentRow.GetCell(_sheet.GetRequiredColumnForLang(lang)).Content;
                    var langXPath         = "div[@data-book=\"" + dataBookLabel + "\" and @lang=\"" + lang + "\"]";
                    var langMatchingNodes = _dataDivElement.SelectNodes(langXPath).Cast <XmlElement>();

                    if (!string.IsNullOrEmpty(langVal))
                    {
                        //Found content in spreadsheet for this language and row
                        if (lang.Equals("*"))
                        {
                            asteriskContentFound = true;
                        }
                        else
                        {
                            specificLanguageContentFound = true;
                        }

                        if (langMatchingNodes.Count() > 0)                         //Found matching node in dom. Update node.
                        {
                            XmlElement matchingNode = langMatchingNodes.First();
                            matchingNode.InnerXml = langVal;
                            if (langMatchingNodes.Count() > 1)
                            {
                                Warn("Found more than one " + dataBookLabel + " element for language "
                                     + lang + " in the book dom. Only the first will be updated.");
                            }
                        }
                        else                         //No node for this language and data-book. Create one from template and add.
                        {
                            XmlElement newNode = (XmlElement)templateNode.CloneNode(deep: true);
                            newNode.SetAttribute("lang", lang);
                            newNode.InnerXml = langVal;
                            AddDataBookNode(newNode);
                        }
                    }
                    else                      //Spreadsheet cell for this row and language is empty. Remove the corresponding node if present.
                    {
                        foreach (XmlNode n in langMatchingNodes.ToArray())
                        {
                            _dataDivElement.RemoveChild(n);
                        }
                    }
                }

                if (RemoveOtherLanguages)
                {
                    HtmlDom.RemoveOtherLanguages(matchingNodes.Cast <XmlElement>().ToList(), _dataDivElement, _sheet.Languages);
                }

                if (asteriskContentFound && specificLanguageContentFound)
                {
                    Warn(dataBookLabel + " information found in both * language column and other language column(s)");
                }
            }
        }