Code Monkey home page Code Monkey logo

proton's People

Contributors

erudel avatar moriquendi avatar rajdeep avatar rjchatfield avatar tomaslinhart avatar vmanot avatar vox-humana avatar yox89 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

proton's Issues

Problem with Strikethrough when changing attributedText

Setting attributedText containing an attribute containing strikethrough results in strikethrough applied to all attributes. Setting the text with an attribute containing underline results in strikethrough=0 appearing in the other attributes. Maybe the fact that both underline and strikethrough attributes use the same value type - namely NSUnderlineStyle.single.rawvalue?

Here are dumps taken from the setter at line 381 of EditorView.attributed text.

First the underline:

(lldb) po newValue
This {
EasiStyle = "Easiwriter.StyleIdentifier(name: Optional("title1"), id: Optional("401D4EBD-B20F-4DE8-8A7F-A32A77F73CB4"))";
NSColor = "<UIDynamicSystemColor: 0x600001eb57c0; name = labelColor>";
NSFont = "<UICTFont: 0x7fbb4fd6f4e0> font-family: "Helvetica Neue"; font-weight: bold; font-style: normal; font-size: 28.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint '(null)'";
}test{
EasiStyle = "Easiwriter.StyleIdentifier(name: Optional("underline"), id: Optional("16C65DC4-94FB-4851-96BE-8FE4FF04EC72"))";
NSColor = "<UIDynamicSystemColor: 0x600001eb57c0; name = labelColor>";
NSFont = "<UICTFont: 0x7fbb4fd6f4e0> font-family: "Helvetica Neue"; font-weight: bold; font-style: normal; font-size: 28.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint '(null)'";
NSUnderline = 1;
}

(lldb) po richTextView.attributedText
▿ Optional

  • some : This {
    EasiStyle = "Easiwriter.StyleIdentifier(name: Optional("largeTitle"), id: Optional("FCDB90A0-557E-42D9-B64A-E18F702DC66A"))";
    NSColor = "<UIDynamicSystemColor: 0x600001eb57c0; name = labelColor>";
    NSFont = "<UICTFont: 0x7fbb3fc3f710> font-family: "Helvetica Neue"; font-weight: bold; font-style: normal; font-size: 34.00pt";
    NSParagraphStyle = "Alignment 1, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint '(null)'";
    NSStrikethrough = 0;
    }test{
    EasiStyle = "Easiwriter.StyleIdentifier(name: Optional("underline"), id: Optional("16C65DC4-94FB-4851-96BE-8FE4FF04EC72"))";
    NSColor = "<UIDynamicSystemColor: 0x600001eb57c0; name = labelColor>";
    NSFont = "<UICTFont: 0x7fbb3fc3f710> font-family: "Helvetica Neue"; font-weight: bold; font-style: normal; font-size: 34.00pt";
    NSParagraphStyle = "Alignment 1, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint '(null)'";
    NSUnderline = 1;
    }

Now the strikethrough case:

(lldb) po newValue
This {
EasiStyle = "Easiwriter.StyleIdentifier(name: Optional("title1"), id: Optional("401D4EBD-B20F-4DE8-8A7F-A32A77F73CB4"))";
NSColor = "<UIDynamicSystemColor: 0x600001eb57c0; name = labelColor>";
NSFont = "<UICTFont: 0x7fbb4fd6f4e0> font-family: "Helvetica Neue"; font-weight: bold; font-style: normal; font-size: 28.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint '(null)'";
}test{
EasiStyle = "Easiwriter.StyleIdentifier(name: Optional("strikethrough"), id: Optional("3B68996A-E9E7-497D-B20C-B4A1DA843DE3"))";
NSColor = "<UIDynamicSystemColor: 0x600001eb57c0; name = labelColor>";
NSFont = "<UICTFont: 0x7fbb4fd6f4e0> font-family: "Helvetica Neue"; font-weight: bold; font-style: normal; font-size: 28.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint '(null)'";
NSStrikethrough = 1;
}

(lldb) po richTextView.attributedText
▿ Optional

  • some : This {
    EasiStyle = "Easiwriter.StyleIdentifier(name: Optional("title1"), id: Optional("401D4EBD-B20F-4DE8-8A7F-A32A77F73CB4"))";
    NSColor = "<UIDynamicSystemColor: 0x600001eb57c0; name = labelColor>";
    NSFont = "<UICTFont: 0x7fbb4fd6f4e0> font-family: "Helvetica Neue"; font-weight: bold; font-style: normal; font-size: 28.00pt";
    NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint '(null)'";
    NSStrikethrough = 1;
    }test{
    EasiStyle = "Easiwriter.StyleIdentifier(name: Optional("strikethrough"), id: Optional("3B68996A-E9E7-497D-B20C-B4A1DA843DE3"))";
    NSColor = "<UIDynamicSystemColor: 0x600001eb57c0; name = labelColor>";
    NSFont = "<UICTFont: 0x7fbb4fd6f4e0> font-family: "Helvetica Neue"; font-weight: bold; font-style: normal; font-size: 28.00pt";
    NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint '(null)'";
    NSStrikethrough = 1;
    }

New tag

Hi,
I really enjoy proton :). I was wondering if you have any plans to create a new tag soon?

Storing & setting of contents in EditorView programatically

I am trying to store and set the data in EditorView to/from core data persistence.

I came across EditorView.contents() to extract the array of EditorContent that I could store to CoreData. However I'm not quite sure how to set this data to the EditorView from the persistent store? Is this the best way to handle data storage from the EditorView?

I don't just want to store the attributed string, but everything needed to recreate the layout of the editor view.

Many thanks for the great work being done with proton, this is a great library and I'm looking forward to where it can go.

Question: How to get current active `EditorView`?

One of the use cases: show typeahead picker while typing following the cursor in the current editor. It should work in nested editors as well.

EditorCommandExecutor uses internal RichTextEditorContext to get activeTextView. However, integrators don't have access to EditorViewContext internal properties.

The only way for now to get active editor I found is somehow detect active firstResponder and try to cast its superview to EditorView. Which is obviously a) not very handy b) exposes internal details of EditorView

No list indicator after pasting

The paragraph style is kept but there is no starting list indicator.

This can be reproduced in the CommandsExampleViewController

  1. Add a list
  2. Paste text (in the screenshot I pasted "List")
  3. Tap enter/return

Simulator Screen Shot - iPhone 12 mini - 2020-10-22 at 15 42 50

EditorViewDelegate didChangeTextAt issue

My app needs to respond to text changes in order to update its model data. I have implemented func editor(_ editor: EditorView, didChangeTextAt range: NSRange) to do this. If I enter some text, place the caret anywhere but the end, then enter a character, the character goes in the correct place but the caret is moved to the end. If I remove the delegate method it works OK (but obviously doesn't update the model). My delegate method does not invoke any Proton methods.

I have tried tracing through the code but can't pinpoint why this is happening, but it looks like it has to do with the way delegate methods are handled.

Question: What is the best way to get notifications from all nested EditorView?

Let's imagine we have VC that holds parent EditorView. It subscribes to its changes via EditorViewDelegate. However, it doesn't receive notifications from nested editors in attachments.

Some posible use cases:

  1. Check changes in content and enable/disable "submit" button while editing content
  2. Show typeahead picker at cursor while typing

Some possible solutions:

  1. Do not subscribe to nested EditorView in EditorContentView and pass main EditorViewDelegate to nested EditorView
  2. Have some proxy delegate in EditorContentView so this view can get notifications and provide specific callbacks like in PanelViewDelegate examples.

Maybe, I missed some other solution. And another question is should it be part of the Core library like some utility code?

Inconsistent List exit behaviour in middle of two non-list paragraphs

Add a line of text and press return
Add another line of text
Create a multi-level list in the middle of these two lines (preferable 5-6 levels deep)
Hit enter at the last element of the list
The list item is outdented
Keep doing it all the way until all lists are exited.

Observed:
Selected range moves outside list at some point without exiting all the levels.

Expected:
List should outdent all the way to zeroth level without loosing focus.

list-exit-issue

Xcode 13

Proton fails to compile with Xcode 13.0 beta. Error: CompileSwiftSources failed with nonzero exit code

EditorListFormattingProvider

I have implemented my own EditorListFormattingProvider. Looking at your code it looks like I need to have a LayoutManagerDelegate that overrides listLineMarkerFor somehow. Is that correct?

As a user, I can move between nested Editors using cursors

I believe this will be important in two scenarios.

Imagine two paragraphs with a Panel in between them which contains a paragraph worth of content. If my cursor is half way along the top paragraph, tapping down should move to “the next line” which is either inside the same paragraph or inside the Panel. I’d expect my cursor to jump into the middle of the first line of the Panel.

Imagine we build a Table with a 2-dimensional array of Editors. If I tap down in a cell, I’d expect the cursor to move into the editor below. Similarly, if I move my cursor to the end of the content within a cell, tapping right should jump to the next cell to the right.

I believe we can leverage the protocol used for “us focusable”.

EditorView & UITextViewDelegate

I am trying to add Proton to a SwiftUI app I've been developing for about a year. It contains a UITextView editor embedded in a UIViewRepresentable class. I want to have bullet/numbered lists and embedded images, which is not easy as I'm sure you know. In fact, trying to solve the problem is how I found Proton. Congratulations on a great piece of work!

I have experimented with the ExampleApp to get a feel for things and have managed to embed a Proton EditorView in my app as a replacement for the UITextView. I can type into it, but that's about all. What I am missing is the Proton equivalents for UITextViewDelegate methods. I am also struggling to detect the EditorView's firstResponder state.

Finally, as you know, the Master package doesn't compile because of the mixed language issue, so I am using version 0.5 at the moment.

Ask framework if selected range is a list

Hi,

Is there a way to ask the framework, for example the ListTextProcessor if the selected range is a list?

This would be good if you have a control to toggle lists on/off.

Thanks for a great framework!
Jonathan

Feature Request: Add `Attachment` to `EditorContentType` case

Currently, we have contents() method that returns [EditorContent]. But its case contains only view, but not an attachment.

public struct EditorContent {
    public let type: EditorContentType
    ...
}

public enum EditorContentType {
    case attachment(name: EditorContent.Name, contentView: UIView, type: AttachmentType)
    ....
}

So if user creates Attachment, then put it into editor there is no designated way to get them back (well except iterating over attributedString of course).

I can create small PR if @rajdeep approves the idea 🙂

SwiftUI support require

Could you please support SWiftUI framework?It will be pretty good~ Thanks for your great job.

Support Multiple `EditorListFormattingProvider`s in an editor

I'm looking into how to support multiple list formats in the same editor. At minimum it feels natural to support ordered and unordered lists in one editor. Before going too far, is this something already in progress? Would it be a welcome addition?

SwiftUI UIRepresentable EditorView extends beyond swiftUI view

I am using Proton with swiftUI through a UIRepresentableView. I am having trouble enabling the scroll functionality when the editor reaches its container size.

I set up my view this way:

struct RepresentableRichTextEditor: UIViewRepresentable {
    
    @Binding var attributedText: NSAttributedString
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    let commandExecutor = EditorCommandExecutor()
    
    func makeUIView(context: Context) -> UIView {
        
        let editor = EditorView()
        editor.delegate = context.coordinator

        //This forces the editor view to scroll however disables the auto layout provided by the representable view
        //editor.translatesAutoresizingMaskIntoConstraints = false 
        //editor.maxHeight = 300

        EditorViewContext.shared.delegate = context.coordinator
        editor.setFocus()
        return editor
    }

    func updateUIView(_ uiView: UIView, context: Context) {

       //Update logic here
        
    }
}

I have tried using .frame(height) in the parent SwiftUI View but this didn't seem to affect the underlying editorView.

Does anyone know how to get scrolling working with SwiftUI?

Many thanks

List formatting issue

I have an issue with displaying a list. The list is displayed OK until I hit enter, after which the output is incorrect.

Here's the list before typing Enter:

Screenshot 2021-04-09 at 11 46 01

Here's the list after:

Screenshot 2021-04-09 at 11 46 18

And here's the NSAttributedString. There is a custom attribute called EasiwriterStyle, but that shouldn't upset it should it?

One
{
    EasiwriterStyle = "Easiwriter.StyleIdentifier(name: \"Body\", id: \"325A872C-7289-4319-8DEB-CE06B111E956\")";
    NSColor = "<UIDynamicSystemColor: 0x600002ae5600; name = labelColor>";
    NSFont = "<UICTFont: 0x7feff6909f30> font-family: \"UICTFontTextStyleBody\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
    "_blockContentType" = "Proton.EditorContent.Name(rawValue: \"_newline\")";
    "_listItem" = ListValue;
}Two{
    EasiwriterStyle = "Easiwriter.StyleIdentifier(name: \"Body\", id: \"325A872C-7289-4319-8DEB-CE06B111E956\")";
    NSColor = "<UIDynamicSystemColor: 0x600002ae5600; name = labelColor>";
    NSFont = "<UICTFont: 0x7feff6909f30> font-family: \"UICTFontTextStyleBody\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
    "_listItem" = ListValue;
}
{
    EasiwriterStyle = "Easiwriter.StyleIdentifier(name: \"Body\", id: \"325A872C-7289-4319-8DEB-CE06B111E956\")";
    NSColor = "<UIDynamicSystemColor: 0x600002ae5600; name = labelColor>";
    NSFont = "<UICTFont: 0x7feff6909f30> font-family: \"UICTFontTextStyleBody\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, 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 -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
    "_blockContentType" = "Proton.EditorContent.Name(rawValue: \"_newline\")";
    "_listItem" = ListValue;
}

FontTraitToggleCommand overwrites last executed command.

Hi,

This bug can be reproduced using the example app using the "Commands" example.

  1. Write any letter.
  2. Select Bold and Italic.
  3. Write any letter.

The letter will now only be italic.

The code in question is the following in FontTraitToggleCommand.

        if selectedText.length == 0 {
            guard let font = editor.attributedText.attribute(.font, at: editor.selectedRange.location - 1, effectiveRange: nil) as? UIFont else { return }
            editor.typingAttributes[.font] = font.toggled(trait: trait)
            return
        }

It only looks at the attributes for the letter before the selected range. If you previously set something to editor.typingAttributes without typing it will be reset.

The code in the previous if-statement does the correct thing for this case.

        if editor.isEmpty || editor.selectedRange == .zero {
            guard let font = editor.typingAttributes[.font] as? UIFont else { return }
            editor.typingAttributes[.font] = font.toggled(trait: trait)
            return
        }

LayoutConstraints issue

My app embeds an EditorView in a SwiftUI UIViewRepresentable struct which is the documented way to use UIKit views. The problem is that the text does not scroll when it reaches the bottom of the view. However, if I close the view and reopen it things wok as expected.

I have found that AutogrowingTextView.LayoutSubviews is only called once when the view opens, so isScrollEnabled is left set to false. Closing and reopening the view sorts this because there is sufficient text available.

The problem seems to be the layoutConstraints because the console contains the following immediately after EditorView.setup is called.

I can overcome the issue by setting isScrollEnabled after every keystroke.

2021-08-08 10:15:17.067778+0100 Easiwriter[3611:91422] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x60000243ae40 h=--& v=--& Proton.EditorView:0x7fb90d839800.height == 759.333 (active)>",
"<NSLayoutConstraint:0x60000240ecb0 V:|-(0)-[Proton.RichTextView:0x7fb90d0b4800] (active, names: '|':Proton.EditorView:0x7fb90d839800 )>",
"<NSLayoutConstraint:0x60000240eb70 Proton.RichTextView:0x7fb90d0b4800.bottom == Proton.EditorView:0x7fb90d839800.bottom (active)>",
"<NSLayoutConstraint:0x600002409ae0 Proton.RichTextView:0x7fb90d0b4800.height >= 926 (active)>"
)

Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600002409ae0 Proton.RichTextView:0x7fb90d0b4800.height >= 926 (active)>

Adding a list between two paragraphs results in the bullet point and indentation to disappear

Trying to add a list in between two existing paragraphs results in an unexpected behaviour. Executing the ListCommand renders an indented bullet point between the two paragraphs but as soon as a character is entered, both the bullet point and the indentation disappear.

Repro steps:

  1. Enter "Text", hit enter and type "Text" again
  2. Move the cursor to the end of the first "Text"
  3. Hit enter
  4. Execute ListCommand to start a new list
  5. Type any character

Expected behaviour:
The entered test is drawn next to the indented bullet point

Actual behaviour:
The bullet point and the indentation disappears.

V0.6.0 won't compile with Xcode 12.5

Just upgraded Xcode and Proton's ObjC code has stopped compiling - NS_ASSUME_NONNULL_BEGIN unknown.

I've tried going back to v0.5.0 but that won't compile because ListParser is not implemented in that version. So I'm stuck, although I could copy the ListParser code as a workaround.

ProtonExtensions.framework: Introduce a “Standard Library” of common plugins

This repo currently contains the core Editor as a framework and the example project. I believe there is space for a framework which contains text processors and commands for common editor behaviour.

  • H1/2/3/4/5/6
  • Bold/Italics/Strike-through
  • Bullet point

Implementing the Text Processor for markdown (* _ #) would be great. Additionally and separately we can co-develop a Command for allowing the Integrator to implement a key command or UIButton action.

These ProtonExtensions are optional and can be ignored by the Integrator - but it is assumed that these will be valuable to most Editor usages. The Example app in this repo will use these extensions, as well as demoing some exotic examples not suitable for production.

"_blockContentType" doesn't conform to NSSecureCoding

Hi, sorry for bombarding you with issues recently.

I am trying to save the attributedString created by Proton to Core Data. To save the NSAttributedString to core data I'm converting it to NSData using an NSSecureUnarchiveFromDataTransformer. This requires that everything conform to NSSecureCoding before being transformed into NSData. Here lies the problem

I believe the custom NSAttributedString.Key - in my case "_blockContentType" came up a lot - don't conform to NSSecureCoding hence not allowing the NSAttributedString to be stored to core data. Would it be possible to make it conform in some way?

Cursor is bigger than font line height when editor has spacing

When TextView has paragraphSpacingBefore or paragraphSpacing cursor covers this spaces and this seems not right especially when you have line selection.

Screenshots from Example app with these properties are set in paragraphStyle
image
image
PR is coming...

Tab on screen keyboard

Given that there is no tab key on the screen kbd have you any idea how to simulate one given that List Processing depends on it. I can set up an item using UIMenuController, but can't work out how to invoke handleKeyCommand.

How to support multiple list formats

I want to let the user create both ordered and unordered lists but I'm not sure how to support this.

I tried adding a @Binding to the EditorListFormattingProvider but for obvious reasons this affects all lists in the EditorView:

class ListFormattingProvider: EditorListFormattingProvider {

    @Binding var listStyle: ListStyle

    init(listStyle: Binding<ListStyle>) {
        _listStyle = listStyle
    }

    let listLineFormatting: LineFormatting = LineFormatting(indentation: 25, spacingBefore: 0)

    func listLineMarkerFor(editor: EditorView, index: Int, level: Int, previousLevel: Int, attributeValue: Any?) -> ListLineMarker {

        switch listStyle {
        case .bullet:
            return BulletSequenceProvider().value(at: index)
        case .numbered:
            if level == 1 {
                return NumberSequenceProvider().value(at: index)
            } else {
                return DashSequenceProvider().value(at: index)
            }
        }


    }
}

Is there a way to do this?
Thank you

Can I register a type of command, but not an instance?

I'd like to filter some types of commands for some editors. registeredCommands seems the right place to do it.
However, EditorView::isCommandRegistered checks for instance equality but not for type equality. So, for example, if I don't have exact instance of command (mention with some userId is a good example) I can't register it and then it won't be executed.
Theoretically, I can skip this check by calling directly command.execute(on editor: EditorView), but I don't know active editor. So if I need to execute command from keyboard shortcut or toolbar button I need to find active EditorView first, which is quite hard (see #27)

Placeholder doesn't appear after text deletion

Before TextStorage replacement in #66 deleteBackward caused didCompleteLayout layout manager delegate call which has updatePlaceholderVisibility inside.

image

However, after this TextStorage update didCompleteLayout isn't being called anymore and after removing the last character placeholder doesn't appear.

Trying to figure out why it happens 🤔

Range exception on deleting panel attachment from the inside

Steps:

  • Open ExampleApp
  • Insert panel
  • Remove empty line after the inserted panel
  • Put cursor back inside the panel
  • Press backspace once to delete the panel
  • Press backspace second time to trigger the crash

I suspect that before calling deleteBackward in parent RichTextView selectedRange hasn't been update and instead of empty range from 0 position contains empty range from 1 position. Not sure what's the right way to update this property 🤔

ListCommand issues

My app uses a style mechanism similar to the one in Pages. To this end it maintains model data describing the style structure of each document. This data is used to generate the attributed text whenever necessary. The issue I have faced is that Proton keeps the nesting structure of lists close to its chest, so it is impossible to regenerate it from model data. I have resolved this for now by saving a copy of the attributed text for each list and replacing it when the document is reloaded/updated. This is not ideal, but does work.

The other issue that I have yet to resolve is how to detect (a) double returns terminating a list and (b) backspacing into a list. It would be great if events could be signalled/state maintained so that these changes can be identified. Maybe this is already possible and I just haven't found it.

List Items - bullets not displayed

I'm trying to get lists working. The attributed text looks the same as that produced by the example app, but the bullets don't appear, so I guess I'm missing a step somewhere. I've tried setting the listItem value to a bullet character and also the string "listItemValue".

I've traced through the code but can't see what's going wrong, although I did come across a TODO that questions the code at line 141 of LayoutManager.

Here's the attributed text for three lines:

Line 1{
NSColor = "<UIDynamicSystemColor: 0x60000318dc00; name = labelColor>";
NSFont = "<UICTFont: 0x7ffb9e42c4f0> font-family: "Helvetica"; font-weight: normal; font-style: normal; font-size: 12.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 12/24, LineHeightMultiple 1, 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 -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
"_listItem" = listItemValue;
}
{
NSColor = "<UIDynamicSystemColor: 0x60000318dc00; name = labelColor>";
NSFont = "<UICTFont: 0x7ffb9e42c4f0> font-family: "Helvetica"; font-weight: normal; font-style: normal; font-size: 12.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 12/24, LineHeightMultiple 1, 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 -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
"_blockContentType" = "Proton.EditorContent.Name(rawValue: "_newline")";
"_listItem" = listItemValue;
}Line 2{
NSColor = "<UIDynamicSystemColor: 0x60000318dc00; name = labelColor>";
NSFont = "<UICTFont: 0x7ffb9e42c4f0> font-family: "Helvetica"; font-weight: normal; font-style: normal; font-size: 12.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 12/24, LineHeightMultiple 1, 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 -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
"_listItem" = listItemValue;
}
{
NSColor = "<UIDynamicSystemColor: 0x60000318dc00; name = labelColor>";
NSFont = "<UICTFont: 0x7ffb9e42c4f0> font-family: "Helvetica"; font-weight: normal; font-style: normal; font-size: 12.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 12/24, LineHeightMultiple 1, 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 -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
"_blockContentType" = "Proton.EditorContent.Name(rawValue: "_newline")";
"_listItem" = listItemValue;
}Line 3{
NSColor = "<UIDynamicSystemColor: 0x60000318dc00; name = labelColor>";
NSFont = "<UICTFont: 0x7ffb9e42c4f0> font-family: "Helvetica"; font-weight: normal; font-style: normal; font-size: 12.00pt";
NSParagraphStyle = "Alignment 0, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 12/24, LineHeightMultiple 1, 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 -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0";
"_listItem" = listItemValue;
}

Here's a screenshot:
Screenshot 2021-01-07 at 13 09 07

NSRangeException when using lists

Hi, this is a crash that is 100% reproducible in the sample app in the "Commands" example.

  1. Tap "List" command.
  2. Tap enter.
  3. Tap "List" command again
  4. Tap enter again
  5. Crash
2021-05-14 08:34:40.949847+0200 ExampleApp[4044:79319] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSBigMutableString _getBlockStart:end:contentsEnd:forRange:stopAtLineSeparators:]: Range {4, 0} out of bounds; string length 3'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff20422fba __exceptionPreprocess + 242
	1   libobjc.A.dylib                     0x00007fff20193ff5 objc_exception_throw + 48
	2   Foundation                          0x00007fff2084c066 -[NSString _getBlockStart:end:contentsEnd:forRange:stopAtLineSeparators:] + 900
	3   Foundation                          0x00007fff2084c66a -[NSString paragraphRangeForRange:] + 75
	4   UIKitCore                           0x00007fff24a224c0 __58-[UITextInputController setBaseWritingDirection:forRange:]_block_invoke + 86
	5   UIFoundation                        0x00007fff23a5584c -[NSTextStorage coordinateEditing:] + 35
	6   UIKitCore                           0x00007fff24a22361 -[UITextInputController setBaseWritingDirection:forRange:] + 152
	7   UIKitCore                           0x00007fff24a42023 -[UITextView setBaseWritingDirection:forRange:] + 68
	8   UIKitCore                           0x00007fff244bab9b -[UIKeyboardImpl(UIKitInternal) setInitialDirection] + 294
	9   UIKitCore                           0x00007fff244a5ffd -[UIKeyboardImpl completeAddInputString:generateCandidates:] + 124
	10  UIKitCore                           0x00007fff244a5f44 __100-[UIKeyboardImpl addWordTerminator:afterSpace:afterAcceptingCandidate:elapsedTime:executionContext:]_block_invoke + 177
	11  UIKitCore                           0x00007fff244cba5d -[UIKeyboardTaskExecutionContext returnExecutionToParentWithInfo:] + 109
	12  UIKitCore                           0x00007fff2449a41c __55-[UIKeyboardImpl handleKeyboardInput:executionContext:]_block_invoke_2 + 799
	13  UIKitCore                           0x00007fff244cd2a1 -[UIKeyboardTaskEntry execute:] + 147
	14  UIKitCore                           0x00007fff244cbf35 -[UIKeyboardTaskQueue continueExecutionOnMainThread] + 310
	15  Foundation                          0x00007fff2085cd08 __NSThreadPerformPerform + 204
	16  CoreFoundation                      0x00007fff20390ede __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
	17  CoreFoundation                      0x00007fff20390dd6 __CFRunLoopDoSource0 + 180
	18  CoreFoundation                      0x00007fff2039029e __CFRunLoopDoSources0 + 242
	19  CoreFoundation                      0x00007fff2038a9f7 __CFRunLoopRun + 875
	20  CoreFoundation                      0x00007fff2038a1a7 CFRunLoopRunSpecific + 567
	21  GraphicsServices                    0x00007fff2b874d85 GSEventRunModal + 139
	22  UIKitCore                           0x00007fff246c14df -[UIApplication _run] + 912
	23  UIKitCore                           0x00007fff246c639c UIApplicationMain + 101
	24  ExampleApp                          0x000000010e19c8cb main + 75
	25  libdyld.dylib                       0x00007fff2025abbd start + 1
	26  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi: terminating with uncaught exception of type NSException

Installing with SPM fails due to mixed language source files

When trying to include Proton in my project using SPM I get the following error message:
target at '[...]/SourcePackages/checkouts/proton/Proton/Sources' contains mixed language source files; feature not supported

I only get this issue on the master branch. Installing from the 0.5.0 tag works fine.

NumericList Items Don't Initially Render Properly

The pops up on several numbers. I tried to do dig a bit into LayoutManager and drawListItem but failed to really find much.

I also switched out the ListLineMarker and returned a UIImage, the images also failed to render correctly at the same indices.

Simulator Screen Shot - iPhone 11 - 2021-02-19 at 13 07 58

TextStorage should cleanup typeahead attributes for text in 0 location

Steps to reproduce:

  • Open "Text Processors" demo
  • Type "@" as the first character in TextView that will trigger text processor and will change .foregroundColor attribute
  • Remove this character
  • Type any other character which now will be .systemBlue color

Looks like setting . foregroundColor attribute also changes typingAttributes and textColor properties of UITextView. Then UITextView uses these properties for further input. Because there is no text before this range where other attributes can be inherited.
Setting typingAttributes right after cleaning . foregroundColor doesn't help.

Tested in demo project. This is default UITextView behaviour.

Feature Request: Current TextProcessor notification on selection (cursor position) change

To show selected state (formatting option or selected type ahead processor) in a toolbar (by highlighting corresponding button) or to show/hide options picker on changing cursor position.

As a suggestion EditorView can ask TextProcessor for active text processors for current range. Maybe, it requires new method in TextProcessing that return whether this processor should be active in selected range.

Encode/Decode Lists

Hello! Congratulations and thanks for this great UITextView extension.

It seems that lists are not encoded/decoded yet, do you think that will be supported soon? ;)

Best regards,
Franky

Build ExampleApp fails with Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_PREditorContentName"

Trying to build "proton-main.zip" or "proton-0.6.1.zip" ExampleApp fails with:

_Undefined symbols for architecture x86_64:
"OBJC_CLASS$PREditorContentName", referenced from:
objc-class-ref in JSONDecoder.o
objc-class-ref in JSONEncoder.o
objc-class-ref in ParagraphEncoder.o
objc-class-ref in WidthRangeAttachmentExampleViewController.o
objc-class-ref in AutogrowingTextField.o
objc-class-ref in PanelView.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Environment: macOS 10.15.7, Xcode 12.4.

I note that there does not seem to be any build target for ProtonExtensions in the Proton.xcworkspace.

I could find no documentation on how one is supposed to integrate Proton into a project. Shouldn't there be a documented Swift Package Manager URL?

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.