<commit_before>import UIKit
import Gridicons

public protocol TextViewMediaDelegate: class {

    /// This method requests from the delegate the image at the specified URL.
    ///
    /// - Parameters:
    ///     - textView: the `TextView` the call has been made from.
    ///     - url: the url to download the image from.
    ///     - success: when the image is obtained, this closure should be executed.
    ///     - failure: if the image cannot be obtained, this closure should be executed.
    ///
    /// - Returns: the placeholder for the requested image.  Also useful if showing low-res versions
    ///         of the images.
    ///
    func image(forTextView textView: TextView, atUrl url: NSURL, onSuccess success: UIImage -> Void, onFailure failure: Void -> Void) -> UIImage
}

public class TextView: UITextView {

    typealias ElementNode = Libxml2.ElementNode


    // MARK: - Properties: Attachments & Media

    private(set) public lazy var attachmentManager: AztecAttachmentManager = {

        AztecAttachmentManager(textView: self)
    }()

    /// The media delegate takes care of providing remote media when requested by the `TextView`.
    /// If this is not set, all remove images will be left blank.
    ///
    public weak var mediaDelegate: TextViewMediaDelegate? = nil

    // MARK: - Properties: GUI Defaults

    let defaultFont: UIFont
    var defaultMissingImage: UIImage

    // MARK: - Properties: Text Storage

    var storage: AztecTextStorage {
        return textStorage as! AztecTextStorage
    }

    // MARK: - Properties: UIView Overrides

    override public var bounds: CGRect {
        didSet {
            if oldValue.size == bounds.size {
                return
            }

            attachmentManager.resizeAttachments()
        }
    }

    // MARK: - Init & deinit

    public init(defaultFont: UIFont, defaultMissingImage: UIImage) {
        let storage = AztecTextStorage()
        let layoutManager = NSLayoutManager()
        let container = NSTextContainer()

        self.defaultFont = defaultFont
        self.defaultMissingImage = defaultMissingImage

        storage.addLayoutManager(layoutManager)
        layoutManager.addTextContainer(container)
        container.widthTracksTextView = true

        super.init(frame: CGRect(x: 0, y: 0, width: 10, height: 10), textContainer: container)

        startListeningToEvents()
    }

    required public init?(coder aDecoder: NSCoder) {

        defaultFont = UIFont.systemFontOfSize(14)
        defaultMissingImage = Gridicon.iconOfType(.Image)

        super.init(coder: aDecoder)
    }

    deinit {
        stopListeningToEvents()
    }


    // MARK: - UIView Overrides

    public override func didMoveToWindow() {
        super.didMoveToWindow()
        attachmentManager.layoutAttachmentViews()
    }


    // MARK: - Events

    /// Wires all of the Notifications / Delegates required!
    ///
    private func startListeningToEvents() {
        // Notifications
        let nc = NSNotificationCenter.defaultCenter()
        nc.addObserver(self, selector: #selector(textViewDidChange), name: UITextViewTextDidChangeNotification, object: self)

        // Delegates
        layoutManager.delegate = self
        attachmentManager.delegate = self
    }

    private func stopListeningToEvents() {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    // MARK: - Paragraphs

    /// Get the default paragraph style for the editor.
    ///
    /// - Returns: The default paragraph style.
    ///
    func defaultParagraphStyle() -> NSParagraphStyle {<commit_msg>TextView: Fixing Attachment Layout Glitches<commit_after>import UIKit
import Gridicons

public protocol TextViewMediaDelegate: class {

    /// This method requests from the delegate the image at the specified URL.
    ///
    /// - Parameters:
    ///     - textView: the `TextView` the call has been made from.
    ///     - url: the url to download the image from.
    ///     - success: when the image is obtained, this closure should be executed.
    ///     - failure: if the image cannot be obtained, this closure should be executed.
    ///
    /// - Returns: the placeholder for the requested image.  Also useful if showing low-res versions
    ///         of the images.
    ///
    func image(forTextView textView: TextView, atUrl url: NSURL, onSuccess success: UIImage -> Void, onFailure failure: Void -> Void) -> UIImage
}

public class TextView: UITextView {

    typealias ElementNode = Libxml2.ElementNode


    // MARK: - Properties: Attachments & Media

    private(set) public lazy var attachmentManager: AztecAttachmentManager = {

        AztecAttachmentManager(textView: self)
    }()

    /// The media delegate takes care of providing remote media when requested by the `TextView`.
    /// If this is not set, all remove images will be left blank.
    ///
    public weak var mediaDelegate: TextViewMediaDelegate? = nil

    // MARK: - Properties: GUI Defaults

    let defaultFont: UIFont
    var defaultMissingImage: UIImage

    // MARK: - Properties: Text Storage

    var storage: AztecTextStorage {
        return textStorage as! AztecTextStorage
    }

    // MARK: - Properties: UIView Overrides

    override public var bounds: CGRect {
        didSet {
            guard oldValue.size != bounds.size else {
                return
            }

            attachmentManager.resizeAttachments()
        }
    }

    // MARK: - Init & deinit

    public init(defaultFont: UIFont, defaultMissingImage: UIImage) {
        let storage = AztecTextStorage()
        let layoutManager = NSLayoutManager()
        let container = NSTextContainer()

        self.defaultFont = defaultFont
        self.defaultMissingImage = defaultMissingImage

        storage.addLayoutManager(layoutManager)
        layoutManager.addTextContainer(container)
        container.widthTracksTextView = true

        super.init(frame: CGRect(x: 0, y: 0, width: 10, height: 10), textContainer: container)

        startListeningToEvents()
    }

    required public init?(coder aDecoder: NSCoder) {

        defaultFont = UIFont.systemFontOfSize(14)
        defaultMissingImage = Gridicon.iconOfType(.Image)

        super.init(coder: aDecoder)
    }

    deinit {
        stopListeningToEvents()
    }


    // MARK: - UIView Overrides

    public override func didMoveToWindow() {
        super.didMoveToWindow()
        layoutIfNeeded()
        attachmentManager.resizeAttachments()
    }


    // MARK: - Events

    /// Wires all of the Notifications / Delegates required!
    ///
    private func startListeningToEvents() {
        // Notifications
        let nc = NSNotificationCenter.defaultCenter()
        nc.addObserver(self, selector: #selector(textViewDidChange), name: UITextViewTextDidChangeNotification, object: self)

        // Delegates
        layoutManager.delegate = self
        attachmentManager.delegate = self
    }

    private func stopListeningToEvents() {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    // MARK: - Paragraphs

    /// Get the default paragraph style for the editor.
    ///
    /// - Returns: The default paragraph style.
    ///
    func defaultParagraphStyle() -> NSParagraphStyle {
{'fraction_non_alphanumeric': 0.08650804566084445, 'fraction_numerical': 0.002475587952138633, 'mean_word_length': 2.4318074563473338, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '113062', 'n_tokens_mistral': 1988, 'n_tokens_neox': 1866, 'n_words': 586}