/// <summary>
 /// Shift any translationGroup level style setting to child editable divs that lack a style.
 /// This is motivated by the fact HTML/CSS underlining cannot be turned off in child nodes.
 /// So if underlining is enabled for Normal, everything everywhere would be underlined
 /// regardless of style or immediate character formatting.  If a style sets underlining
 /// on, then immediate character formatting cannot turn it off anywhere in a text box that
 /// uses that style.  See https://silbloom.myjetbrains.com/youtrack/issue/BL-6282.
 /// </summary>
 private static void FixGroupStyleSettings(XmlNode pageDiv)
 {
     foreach (
         XmlElement groupElement in
         pageDiv.SafeSelectNodes("descendant-or-self::*[contains(@class,'bloom-translationGroup')]"))
     {
         var groupStyle = HtmlDom.GetStyle(groupElement);
         if (String.IsNullOrEmpty(groupStyle))
         {
             continue;
         }
         // Copy the group's style setting to any child div with the bloom-editable class that lacks one.
         // Then remove the group style if it does have any child divs with the bloom-editable class.
         bool hasInternalEditableDiv = false;
         foreach (XmlElement element in groupElement.SafeSelectNodes("child::div[contains(@class, 'bloom-editable')]"))
         {
             var divStyle = HtmlDom.GetStyle(element);
             if (String.IsNullOrEmpty(divStyle))
             {
                 HtmlDom.AddClass(element, groupStyle);
             }
             hasInternalEditableDiv = true;
         }
         if (hasInternalEditableDiv)
         {
             HtmlDom.RemoveClass(groupElement, groupStyle);
         }
     }
 }
Example #2
0
 // At publish time, we strip out pages with the bloom-enterprise class.
 // But we don't want to do that for comic pages in derivatives. See BL-10586.
 private void StripBloomEnterpriseClassFromComicPages(BookStorage storage)
 {
     foreach (XmlElement pageDiv in storage.Dom.RawDom.SafeSelectNodes("//div[contains(@class,'bloom-page')]"))
     {
         if (HtmlDom.HasClass(pageDiv, "comic"))
         {
             HtmlDom.RemoveClass(pageDiv, "enterprise-only");
         }
     }
 }
        /// <summary>
        /// For each group (meaning they have a common parent) of editable items, we
        /// need to make sure there are the correct set of copies, with appropriate @lang attributes
        /// </summary>
        public static XmlElement MakeElementWithLanguageForOneGroup(XmlElement groupElement, string isoCode)
        {
            if (groupElement.GetAttribute("class").Contains("STOP"))
            {
                Console.Write("stop");
            }

            // If we don't have the relevant language code in this collection, don't make a block for it!
            if (string.IsNullOrEmpty(isoCode))
            {
                return(null);
            }

            XmlNodeList editableChildrenOfTheGroup =
                groupElement.SafeSelectNodes("*[self::textarea or contains(@class,'bloom-editable')]");

            var elementsAlreadyInThisLanguage = from XmlElement x in editableChildrenOfTheGroup
                                                where x.GetAttribute("lang") == isoCode
                                                select x;

            if (elementsAlreadyInThisLanguage.Any())
            {
                //don't mess with this set, it already has a vernacular (this will happen when we're editing a shellbook, not just using it to make a vernacular edition)
                return(elementsAlreadyInThisLanguage.First());
            }

            if (groupElement.SafeSelectNodes("ancestor-or-self::*[contains(@class,'bloom-translationGroup')]").Count == 0)
            {
                return(null);
            }

            var        prototype = editableChildrenOfTheGroup[0] as XmlElement;
            XmlElement newElementInThisLanguage;

            if (prototype == null)             //this was an empty translation-group (unusual, but we can cope)
            {
                newElementInThisLanguage = groupElement.OwnerDocument.CreateElement("div");
                newElementInThisLanguage.SetAttribute("class", "bloom-editable");
                newElementInThisLanguage.SetAttribute("contenteditable", "true");
                if (groupElement.HasAttribute("data-placeholder"))
                {
                    newElementInThisLanguage.SetAttribute("data-placeholder", groupElement.GetAttribute("data-placeholder"));
                }
                groupElement.AppendChild(newElementInThisLanguage);
            }
            else             //this is the normal situation, where we're just copying the first element
            {
                //what we want to do is copy everything in the element, except that which is specific to a language.
                //so classes on the element, non-text children (like images), etc. should be copied
                newElementInThisLanguage = (XmlElement)prototype.ParentNode.InsertAfter(prototype.Clone(), prototype);
                //if there is an id, get rid of it, because we don't want 2 elements with the same id
                newElementInThisLanguage.RemoveAttribute("id");

                // Since we change the ID, the corresponding mp3 will change, which means the duration is no longer valid
                newElementInThisLanguage.RemoveAttribute("data-duration");

                // No need to copy over the audio-sentence markup
                // Various code expects elements with class audio-sentence to have an ID.
                // Both will be added when and if  we do audio recording (in whole-text-box mode) on the new div.
                // Until then it makes things more consistent if we make sure elements without ids
                // don't have this class.
                // Also, if audio recording markup is done using one audio-sentence span per sentence, we won't copy it.  (Because we strip all out the text underneath this node)
                // So, it's more consistent to treat all scenarios the same way (don't copy the audio-sentence markup)
                HtmlDom.RemoveClass(newElementInThisLanguage, "audio-sentence");

                // Nor any need to copy over other audio markup
                // We want to clear up all the audio markup so it's not left in an inconsistent state
                // where the Talking Book JS code thinks it's been initialized already, but actually all the audio-sentence markup has been stripped out :(
                // See BL-8215
                newElementInThisLanguage.RemoveAttribute("data-audiorecordingmode");
                newElementInThisLanguage.RemoveAttribute("data-audiorecordingendtimes");
                HtmlDom.RemoveClass(newElementInThisLanguage, "bloom-postAudioSplit");

                //OK, now any text in there will belong to the prototype language, so remove it, while retaining everything else
                StripOutText(newElementInThisLanguage);
            }
            newElementInThisLanguage.SetAttribute("lang", isoCode);
            return(newElementInThisLanguage);
        }