3 Replies
      Latest reply on Aug 25, 2018 7:23 AM by ManuelMB
      tartempion Level 1 Level 1 (10 points)

        Problem:

         

        It's possible to define how a link should look in a NSTextView using the linkTextAttributes property.

         

        The problem is that this does not apparently let one define how the link should look like when being clicked (or after having been visited).

         

        Question:

         

        Is there some attribute names that can be used to define how the link should look like when it's being clicked?

        • Re: NSTextView > linkTextAttributes when link is being clicked?
          ManuelMB Level 3 Level 3 (175 points)

          NSTextView has the property:

           

          var linkTextAttributes: [NSAttributedString.Key : Any]? { get set }

           

          That is used for:

           

          The attributes used to draw the onscreen presentation of link text.

           

          Link text attributes are applied as temporary attributes to any text with a link attribute.

           

          I managed to change the attributes as follow:

           

          import Cocoa
          
          class ChangeColorVisitedLinksViewController: NSViewController {
          
              @IBOutlet var textView: NSTextView!
              
              var linkRanges = [NSRange]()
              
              override func viewDidLoad() {
                  super.viewDidLoad()
                  textView.delegate = self
                  let string = textView.string
                  let types = NSTextCheckingResult.CheckingType.link
                  
                  let detector = try? NSDataDetector(types: types.rawValue)
                  
                  if let matches = detector?.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)){
                      for match in matches {
                          linkRanges.append(match.range)
                      }
                  }
              }
              
          }
          
          extension ChangeColorVisitedLinksViewController : NSTextViewDelegate{
              func textView(_ textView: NSTextView, clickedOnLink link: Any, at charIndex: Int) -> Bool{
                  for linkRange in linkRanges{
                      if linkRange.contains(charIndex){
                          guard let textStorage = textView.textStorage else { return false }
                          textStorage.setAttributes([NSAttributedString.Key.foregroundColor: NSColor.red] , range: linkRange)
                      }
                  }
                    return false
              }
          }
          
          
            • Re: NSTextView > linkTextAttributes when link is being clicked?
              tartempion Level 1 Level 1 (10 points)

              Interesting solutions for the visited links. But this unfortunately does not solve the "being clicked" color problem.

                • Re: NSTextView > linkTextAttributes when link is being clicked?
                  ManuelMB Level 3 Level 3 (175 points)

                  If you would like to have a different color for the "being clicked", you need something like this.

                   

                  It use red color for visited links and green color for  "being clicked" link.

                   

                  import Cocoa
                  
                  class LinkRangesWithVisitedStatus{
                      let range: NSRange
                      var visited: Bool = false
                      init(range: NSRange){
                          self.range = range
                      }
                  }
                  
                  class ViewController: NSViewController {
                      
                      @IBOutlet var textView: NSTextView!
                  
                      var linkRangesWithVisitedStatus = [LinkRangesWithVisitedStatus]()
                  
                      override func viewDidLoad() {
                          super.viewDidLoad()
                          textView.delegate = self
                          let string = textView.string
                  
                          let types = NSTextCheckingResult.CheckingType.link
                          
                          let detector = try? NSDataDetector(types: types.rawValue)
                  
                          if let matches = detector?.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)){
                  
                              for match in matches {
                                  linkRangesWithVisitedStatus.append(LinkRangesWithVisitedStatus(range:match.range))
                              }
                          }
                      }
                  }
                  
                  extension ViewController : NSTextViewDelegate{
                      func textView(_ textView: NSTextView, clickedOnLink link: Any, at charIndex: Int) -> Bool{
                          for linkRangeWithVisitedStatus in linkRangesWithVisitedStatus{
                              
                              guard let textStorage = textView.textStorage else { return true }
                              
                              if linkRangeWithVisitedStatus.visited == true {
                                  textStorage.setAttributes([NSAttributedString.Key.foregroundColor: NSColor.red] , range: linkRangeWithVisitedStatus.range) // The previous visited links
                              }
                              
                              if linkRangeWithVisitedStatus.range.contains(charIndex){
                                  textStorage.setAttributes([NSAttributedString.Key.foregroundColor: NSColor.green] , range: linkRangeWithVisitedStatus.range) // The link being clicked
                                  linkRangeWithVisitedStatus.visited = true
                              }
                          }
                          return true
                      }
                  }