Andrew-Chen-Wang / RichEditorView

Rich Text Editor in Swift. Newly Featured Code and Swift 5 compatible of cjwirth/RichEditorView.
BSD 3-Clause "New" or "Revised" License
134 stars 59 forks source link

Text color, background text color, image, video, and tables functions aren't working. #23

Open lucychen0103 opened 2 years ago

lucychen0103 commented 2 years ago

I can click on the icon but the functions aren't working. Does anyone have any insight?

Andrew-Chen-Wang commented 2 years ago

Logs/output/the HTML itself would be great!

Andrew-Chen-Wang commented 2 years ago

Are you using the Example RichEditorProject? The code for actually implementing the video is a customizable feature from a delegate. Take a look how we implement the insert link functionality. Due to different people's different needs, it was not implemented.

Here's what you could do:

Unfortunately, it's too tailored to whatever your needs are, so the example doesn't provide. I guess I could provide an example later.

In the example app, just append the following:

<div><video class='video-js' controls preload='auto'  data-setup='{}'><source src='https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_1MB.mp4'></source></video></div>

Hope that helps!

lucychen0103 commented 2 years ago

Thanks @Andrew-Chen-Wang! I'll take a swipe at implementing the video function tomorrow after I wake up. In the meantime, may you redirect me to where the code for insertImage is being called so that I may troubleshoot? I can't find any of the implementations for the functions that are being called when the icons are clicked for some reason. Do I need to download the original repo as well to access? Thanks!

Andrew-Chen-Wang commented 2 years ago

You should be able to find the insertImage function in Sources/RichEditorView/RichEditorView.swift and find the actual delegates at the top of the file like where the link delegate method is.

So the way the editor works is that every time you press an icon, we run a swift method that calls runJS in Sources/RichEditorView/RichEditorView.swift. This executes a javascript function in a javascript file called rich_editor.js under Resources/editor (hence you can decorate the editor using the rich_editor.html file and even include other JS or CSS files). We're running all this in a WKWebView.

Unless it's private, do you mind creating a PR with whatever you come up with in the example RichEditorProject? You can play around with the example by opening the XCode project under the Example dir. Only if you don't mind tho!

And yea np! but also hope that helps :P

lucychen0103 commented 2 years ago

@Andrew-Chen-Wang With your help, I finished all of the functions that weren't working before. I'm not using the example RichEditorProject so I can't make a PR but here is my code!

extension TextController: RichEditorToolbarDelegate, UIImagePickerControllerDelegate, UIColorPickerViewControllerDelegate {

//had to resize image because otherwise it would be too big
    func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage {

       let scale = newWidth / image.size.width
       let newHeight = image.size.height * scale
        UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
        image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()!
       UIGraphicsEndImageContext()

       return newImage
   }

//insert image and video functionality 
    func richEditorToolbarInsertImage(_ toolbar: RichEditorToolbar){
        var imagePicker = UIImagePickerController()
        if UIImagePickerController.isSourceTypeAvailable(.photoLibrary){
              imagePicker.delegate = self
              imagePicker.sourceType = .photoLibrary
              imagePicker.allowsEditing = false
              present(imagePicker, animated: true, completion: nil)
          }
    }

    func richEditorToolbarInsertVideo(_ toolbar: RichEditorToolbar){
        var picker = UIImagePickerController()
        picker.delegate = self
        picker.sourceType = .savedPhotosAlbum
        picker.mediaTypes = ["public.movie"]
        picker.allowsEditing = false
        present(picker, animated: true, completion: nil)
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true, completion: nil)
        let randomInt = Int.random(in: 0..<10000)
        if((info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerMediaType") ] as! String) == "public.movie" ){
          // Video file
            let videoURL = info[UIImagePickerController.InfoKey(rawValue: UIImagePickerController.InfoKey.mediaURL.rawValue) ] as? NSURL
             print(videoURL!)
            toolbar.editor?.insertVideo(vidURL: (videoURL?.absoluteString)!, posterURL: "", isBase64: false)
        }
        else{
            if var image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
                guard let imageURL = NSURL(fileURLWithPath:
                                            NSTemporaryDirectory()).appendingPathComponent(String(randomInt) + ".png") else {
                    return
                }
                image = resizeImage(image: image, newWidth: view.bounds.width)
                let pngData = image.pngData();
                do {
                    try pngData?.write(to: imageURL);
                } catch {
                    print("can't save image")
                }
                toolbar.editor?.insertImage(imageURL.absoluteString, alt: "(image can't be shown)")
            }
        }

    }

//text and background color 
    func richEditorToolbarChangeTextColor(_ toolbar: RichEditorToolbar) {
        let colorPicker = UIColorPickerViewController()
        colorPicker.delegate = self
        changeTextColor = true
        present(colorPicker, animated: true, completion: nil)
    }

    func richEditorToolbarChangeBackgroundColor(_ toolbar: RichEditorToolbar) {
        let colorPicker = UIColorPickerViewController()
        colorPicker.delegate = self
        changeBackgroundColor = true
        present(colorPicker, animated: true, completion: nil)
    }

    func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) {
        if changeTextColor {
            toolbar.editor?.setTextColor(viewController.selectedColor)
            changeTextColor = false
        }
        else if changeBackgroundColor {
            toolbar.editor?.setTextBackgroundColor(viewController.selectedColor)
            changeBackgroundColor = false
        }

    }

//insert table function, made an alert controller to customize the height and width of table
    func richEditorToolbarInsertTable(_ toolbar: RichEditorToolbar) {
        let alertController = UIAlertController(title: "Enter height and width", message: "", preferredStyle: .alert)
        let confirmAction = UIAlertAction(title: "Insert", style: .default) { (_) in
            var height = alertController.textFields?[0].text
            let width = alertController.textFields?[1].text
            toolbar.editor?.insertTable(width: Int(width!) ?? 2, height: Int(height!) ?? 2)
            self.editorView.focus()
        }
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
        alertController.addAction(confirmAction)
        alertController.addAction(cancelAction)
        self.present(alertController, animated: true, completion: nil)
        confirmAction.isEnabled = true
        let heightPH = "Height (required)"
        let widthPH = "Width (required)"
        alertController.addTextField { (textField) in
            textField.placeholder = heightPH
        }
        alertController.addTextField { (textField) in textField.placeholder = widthPH }
    }

//already here, found in example RichEditorProject not written by me 
    func isURLValid(url: String?) -> Bool {
        if(url?.hasPrefix("http://") ?? false || url?.hasPrefix("https://") ?? false) { return true }
        return false
    }

    func richEditorToolbarInsertLink(_ toolbar: RichEditorToolbar) {
        let alertController = UIAlertController(title: "Enter link and text", message: "You can leave the text empty to only show a clickable link", preferredStyle: .alert)
        let confirmAction = UIAlertAction(title: "Insert", style: .default) { (_) in
            var link = alertController.textFields?[0].text
            let text = alertController.textFields?[1].text
            if link?.last != "/" { link = link! + "/" }
            toolbar.editor?.insertLink(href: link!, text: text ?? link!)
            self.editorView.focus()
        }
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
        alertController.addAction(confirmAction)
        alertController.addAction(cancelAction)
        self.present(alertController, animated: true, completion: nil)
        confirmAction.isEnabled = false
        let linkPH = "Link (required)"
        let txtPH = "Text (Clickable text that redirects)"
        toolbar.editor?.hasRangeSelection(handler: { r in
            if r == true {
                alertController.addTextField { (textField) in
                    textField.placeholder = linkPH
                    toolbar.editor?.getSelectedHref(handler: { a in
                        if a?.last != "/" {
                            textField.text = nil
                        } else {
                            if self.isURLValid(url: a) == true {
                                textField.text = a
                            }
                        }
                    })
                    NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: OperationQueue.main) { (notification) in
                        if self.isURLValid(url: textField.text) == true {
                            confirmAction.isEnabled = textField.hasText
                        } else {
                            confirmAction.isEnabled = false
                        }
                    }
                }
                alertController.addTextField { (textField) in
                    textField.placeholder = txtPH
                    toolbar.editor?.getSelectedText(handler: { a in
                        textField.text = a
                    })
                }
            } else {
                alertController.addTextField { (textField) in
                    textField.placeholder = linkPH
                    NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: OperationQueue.main) { (notification) in
                        if self.isURLValid(url: textField.text) == true {
                            confirmAction.isEnabled = textField.hasText
                        } else {
                            confirmAction.isEnabled = false
                        }
                    }
                }
                alertController.addTextField { (textField) in textField.placeholder = txtPH }
            }
        })
    }
}
Andrew-Chen-Wang commented 2 years ago

@lucychen0103 this is great! Thanks so much!

rmi111 commented 2 years ago

What is TextControlleer here?

lucychen0103 commented 2 years ago

@rmi111 It's just a class. You can change the name