Search code examples
iosobjective-cuiwebviewrich-text-editornsundomanager

How to implement undo/redo in UIWebView


I am developing an app which has rich text editor feature. On top of ZSSRichTextEditor I have written my editor code. Here my editor is UIWebView which will be injected by javascript code to support/edit the rich text content.

ZSSRichTextEditor has undo/redo feature but it does not comply with my requirement. So i started to implement undo/redo feature by own.

After I went through UndoManager I came to know that implementing undo/redo will not be a that much headache as Apple helps lot for us. If we register it in proper place then UndoManager will take care of all other thing. But here I am struggling how/where to register UndoManger for editable UIWebView.

There are so many examples to implement undo/redo in UITextView but I don’t find anything for editable UIWebView

Can you some one please guide me on this?


Solution

  • First, create two properties for the history like so:

    @property (nonatomic, strong) NSMutableArray *history;
    @property (nonatomic) NSInteger currentIndex;
    

    Then what I would do is use subclass ZSSRichTextEditor so that you get delegate calls when a key is pressed or action is done. Then on every delegate call, you can use:

    - (void)delegateMethod {
        //get the current html
        NSString *html = [self.editor getHTML];
        //we've added to the history
        self.currentIndex++;
        //add the html to the history
        [self.history insertObject:html atIndex:currentIndex];
        //remove any of the redos because we've created a new branch from our history
        self.history = [NSMutableArray arrayWithArray:[self.history subarrayWithRange:NSMakeRange(0, self.currentIndex + 1)]];
    }
    
    - (void)redo {
       //can't redo if there are no newer operations
       if (self.currentIndex >= self.history.count)
           return;
       //move forward one
       self.currentIndex++;
       [self.editor setHTML:[self.history objectAtIndex:self.currentIndex]];
    }
    
    - (void)undo {
       //can't undo if at the beginning of history
       if (self.currentIndex <= 0)
           return;
       //go back one
       self.currentIndex--;
       [self.editor setHTML:[self.history objectAtIndex:self.currentIndex]];
    }
    

    I would also use some sort of FIFO (First in First out) method to keep the size of the history smaller than 20 or 30 so that you don't have these crazy long strings in memory. But that's up to you depending on how long the content is in the editor. Hope this all makes sense.