Code Monkey home page Code Monkey logo

Comments (5)

danielallsopp avatar danielallsopp commented on May 23, 2024 1

Thanks for your suggestions @rajdeep, I'm going to go through my code now and see if I can use them to get around my issue. I will get back to you as soon as possible with my findings.

from proton.

rajdeep avatar rajdeep commented on May 23, 2024

hi @danielallsopp,
this is by design in iOS. In attributedString representation, each new line is a start of a new paragraph. I am not sure I understand your question correctly as for both the cases, you should be getting a new paragraph for each line of the text. I verified this again using the following in my tests:

  var list = [ListItem]()

        let indent: CGFloat = 50

        list.append(ListItem(text: NSAttributedString(string: "Item 1"), level: 1, attributeValue: 1))
        list.append(ListItem(text: NSAttributedString(string: "Item 2"), level: 1, attributeValue: 1))
        //         list.append(ListItem(text: NSAttributedString(string: "Item 2", attributes: [.font: UIFont.systemFont(ofSize: 18, weight: .bold)]), level: 1, attributeValue: 1))
        list.append(ListItem(text: NSAttributedString(string: "Item 3"), level: 1, attributeValue: 2))

        let text = ListParser.parse(list: list, indent: indent)
        print(text)

The output in terms of structure is same if you use the commented line for "Item 2" or the uncommented one.

Are you able to provide a test that can help me understand the issue better?

Also, you may consider the following function in combination with what you are using which will still allow you to get the range of text for each of the list item, which you can possibly use to append list tags:

func parse(attributedString: NSAttributedString, indent: CGFloat = 25) -> [(range: NSRange, listItem: ListItem)] 

from proton.

danielallsopp avatar danielallsopp commented on May 23, 2024

Hi @rajdeep Thanks for getting back to me.

each new line is a start of a new paragraph

This is not the case from my tests though; if I create a list with no formatting on any of the list items, then the whole list, i.e. each list item, is sent in one paragraph block from the string.enumerateInlineContents().forEach call, like this:

​these
are
passed
in
one
paragraph {
    NSColor = "<UIDynamicCatalogSystemColor: 0x600002b69000; name = labelColor>";
    NSFont = "<UICTFont: 0x7f809e1a8530> font-family: \".SFUI-Regular\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 25, TailIndent 0, FirstLineHeadIndent 25, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection 0, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    "_listItem" = "TextEditorFormat.unorderedList";
}), enclosingRange: Optional({0, 35}))

When I parse the paragraph with ListParser then yes, each item is extracted one at a time. This way I can easily create an unordered list in HTML, because if I know the paragraph is a list I can create opening and closing tags:

<ul>
ParseList -> Create an li for each list item
</ul>

When there is formatting on the list items then I don't get the whole list in one paragraph, i.e. in the string.enumerateInlineContents().forEach block each line item is sent as a new paragraph which makes it impossible to know when to open and close the list with HTML tags. For example:

​these
{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600002b69000; name = labelColor>";
    NSFont = "<UICTFont: 0x7f809e1a8530> font-family: \".SFUI-Regular\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 25, TailIndent 0, FirstLineHeadIndent 25, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection 0, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    "_listItem" = "TextEditorFormat.unorderedList";
}), enclosingRange: Optional({0, 7}))

are{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600002b69000; name = labelColor>";
    NSFont = "<UICTFont: 0x7f809e19e350> font-family: \".SFUI-SemiboldItalic\"; font-weight: bold; font-style: italic; font-size: 17.00pt";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 25, TailIndent 0, FirstLineHeadIndent 25, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection 0, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    "_listItem" = "TextEditorFormat.unorderedList";
}), enclosingRange: Optional({7, 3}))

passed{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600002b69000; name = labelColor>";
    NSFont = "<UICTFont: 0x7f809d7ca790> font-family: \".SFUI-RegularItalic\"; font-weight: normal; font-style: italic; font-size: 17.00pt";
    NSParagraphStyle = "Alignment 4, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 25, TailIndent 0, FirstLineHeadIndent 25, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection 0, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    "_listItem" = "TextEditorFormat.unorderedList";
}), enclosingRange: Optional({11, 6}))

etc.

Let me know if you need any more information and I'll try and put a test project together. Parsing the list isn't a problem, but knowing when to insert the opening and closing list tags is.

from proton.

rajdeep avatar rajdeep commented on May 23, 2024

@danielallsopp, this is by design in case of enumerateInlineContents. How I see this being used is to get fine grain information of the contents, including text, for something like persistence to JSON or similar.

If you notice, in the example you shared, the font for each line is different, even though paragraphStyle is the same:

​these
{
 ...
    NSFont = "<UICTFont: 0x7f809e1a8530> **font-family: \".SFUI-Regular\";** font-weight: normal; font-style: normal; font-size: 17.00pt";
...

are{
 ...
    NSFont = "<UICTFont: 0x7f809e19e350> font-family: \".SFUI-SemiboldItalic\"; font-weight: bold; font-style: italic; font-size: 17.00pt";
    ...
passed{
    ...
    NSFont = "<UICTFont: 0x7f809d7ca790> font-family: \".SFUI-RegularItalic\"; font-weight: normal; font-style: italic; font-size: 17.00pt";
...
etc.

If you would like to get info individually, you may try one of the following:

  • Create a copy of your attributedString and drop attributes like font that may be different and then, read the text back.
  • Use your own function using attributedString.enumerateAttribute on .paragraphStyle without specifying option for longestEffectiveRangeNotRequired. It's because of this option that the string gets broken down when any of the attribute in given range is different.
  • Create your own function and split text based on newlines. Each range of text is one paragraph then and you can inspect or process each line individually per your requirement.

Also, for your purposes, can you not just use the contents parsed by ListParser and take the ranges from that to append the list start and end tags?

Hope this helps.

If you feel I am still missing the context, I think best would be to provide a failing unit test that I can look at to understand your requirements. 🙂

from proton.

rajdeep avatar rajdeep commented on May 23, 2024

please feel to reopen this issue if any further discussion is required.

from proton.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.