Bladeren bron

new Logic of Rich text

alqindiirsyam 2 jaren geleden
bovenliggende
commit
735e115856
1 gewijzigde bestanden met toevoegingen van 177 en 128 verwijderingen
  1. 177 128
      appbuilder-ios/NexilisLite/NexilisLite/Source/Extension.swift

+ 177 - 128
appbuilder-ios/NexilisLite/NexilisLite/Source/Extension.swift

@@ -632,156 +632,181 @@ extension String {
         let font = UIFont.systemFont(ofSize: 12)
         let textUTF8 = String(self.utf8)
         let finalText = NSMutableAttributedString(string: textUTF8, attributes: [NSAttributedString.Key.font: font])
-        var boolStar = false
-        var startStar = 0
-        var endStar = 0
+        let boldSign: Character = "*"
+        let italicSign: Character = "_"
+        let underlineSign: Character = "^"
+        let strikethroughSign: Character = "~"
         
-        var boolItalic = false
-        var startItalic = 0
-        var endItalic = 0
-        
-        var boolUnderLine = false
-        var startUnderLine = 0
-        var endUnderLine = 0
-        
-        var boolStrike = false
-        var startStrike = 0
-        var endStrike = 0
+        //Bold
+        let rangeBold = getRangeOfWordWithSign(sentence: textUTF8, sign: boldSign)
+        if rangeBold.count > 0 {
+            var lastFirstRange = 0
+            var countRemoveBoldSign = 0
+            var continueCheckingBold = false
+            var totalEmoji = 0
+            for i in 0..<rangeBold.count {
+                if lastFirstRange == 0 {
+                    if (rangeBold[i].startIndex == 0 || checkCharBeforeAfter(char: textUTF8.substring(from: rangeBold[i].startIndex - 1, to: rangeBold[i].startIndex - 1))) {
+                        lastFirstRange = rangeBold[i].startIndex
+                        continueCheckingBold = true
+                    } else {
+                        continueCheckingBold = false
+                    }
+                }
+                if !continueCheckingBold {
+                    continue
+                }
+                if (rangeBold[i].endIndex == textUTF8.count - 1 || checkCharBeforeAfter(char: textUTF8.substring(from: rangeBold[i].endIndex + 1, to: rangeBold[i].endIndex + 1))) {
+                    let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveBoldSign), to: rangeBold[i].endIndex - (2*countRemoveBoldSign)).countEmojiCharacter()
+                    totalEmoji = totalEmoji + countEmoji
+                    finalText.addAttribute(.font, value: font.bold, range: NSRange(location: lastFirstRange - (2*countRemoveBoldSign), length: rangeBold[i].endIndex - lastFirstRange + totalEmoji + 1))
+                    if !isEditing{
+                        finalText.mutableString.replaceOccurrences(of: "\(boldSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange - (2*countRemoveBoldSign), length: 1 + countEmoji))
+                        finalText.mutableString.replaceOccurrences(of: "\(boldSign)", with: "", options: .literal, range: NSRange(location: rangeBold[i].endIndex - 1 - (2*countRemoveBoldSign) + countEmoji, length: 1 + countEmoji))
+                        countRemoveBoldSign += 1
+                    } else {
+                        finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + (totalEmoji == 0 ? 0 : totalEmoji - 1), length: 1))
+                        finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeBold[i].endIndex + totalEmoji, length: 1))
+                    }
+                    lastFirstRange = 0
+                }
+            }
+        }
         
-        var firstCount = 0
-        var lastCount = textUTF8.count - 1
-        if isEditing {
-            firstCount = first
-            lastCount = last
+        //Italic
+        let textAfterbold = finalText.string
+        let rangeItalic = getRangeOfWordWithSign(sentence: textAfterbold, sign: italicSign)
+        if rangeItalic.count > 0 {
+            var lastFirstRange = 0
+            var countRemoveItalicSign = 0
+            var continueCheckingItalic = false
+            var totalEmoji = 0
+            for i in 0..<rangeItalic.count {
+                if lastFirstRange == 0 {
+                    if (rangeItalic[i].startIndex == 0 || checkCharBeforeAfter(char: textAfterbold.substring(from: rangeItalic[i].startIndex - 1, to: rangeItalic[i].startIndex - 1))) {
+                        lastFirstRange = rangeItalic[i].startIndex
+                        continueCheckingItalic = true
+                    } else {
+                        continueCheckingItalic = false
+                    }
+                }
+                if !continueCheckingItalic {
+                    continue
+                }
+                if (rangeItalic[i].endIndex == textAfterbold.count - 1 || checkCharBeforeAfter(char: textAfterbold.substring(from: rangeItalic[i].endIndex + 1, to: rangeItalic[i].endIndex + 1))) {
+                    let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveItalicSign), to: rangeItalic[i].endIndex - (2*countRemoveItalicSign)).countEmojiCharacter()
+                    totalEmoji = totalEmoji + countEmoji
+                    finalText.addAttribute(.font, value: font.italic, range: NSRange(location: lastFirstRange - (2*countRemoveItalicSign), length: rangeItalic[i].endIndex - lastFirstRange + totalEmoji + 1))
+                    if !isEditing{
+                        finalText.mutableString.replaceOccurrences(of: "\(italicSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange - (2*countRemoveItalicSign), length: 1 + countEmoji))
+                        finalText.mutableString.replaceOccurrences(of: "\(italicSign)", with: "", options: .literal, range: NSRange(location: rangeItalic[i].endIndex - 1 - (2*countRemoveItalicSign) + countEmoji, length: 1 + countEmoji))
+                        countRemoveItalicSign += 1
+                    } else {
+                        finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + (totalEmoji == 0 ? 0 : totalEmoji - 1), length: 1))
+                        finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeItalic[i].endIndex + totalEmoji, length: 1))
+                    }
+                    lastFirstRange = 0
+                }
+            }
         }
         
-        if textUTF8.count > 0 {
-            for i in firstCount...lastCount {
-                //BOLD
-                if String(textUTF8.substring(from: i, to: i)) == "*" && !boolStar {
-                    boolStar = true
-                    startStar = i
-                    startStar = startStar - (textUTF8.count - finalText.string.count)
-                } else if String(textUTF8.substring(from: i, to: i)) == "*" && boolStar {
-                    endStar = i
-                    endStar = endStar - (self.count - finalText.string.count)
-                    //!String(textUTF8.substring(from: startStar + 1, to: endStar)).trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
-                    if (startStar - 1 == -1 || checkCharBeforeAfter(char: String(finalText.string.substring(from: startStar - 1, to: startStar - 1)))) && (endStar + 1 == finalText.string.count || checkCharBeforeAfter(char: String(finalText.string.substring(from: endStar + 1, to: endStar + 1)))) && endStar - startStar != 1 && !String(finalText.string.substring(from: startStar + 1, to: endStar - 1)).trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
-                        let countEmoji = finalText.string.countEmojiCharacter()
-                        finalText.addAttribute(.font, value: font.bold, range: NSRange(location: startStar, length: endStar - startStar + countEmoji + 1))
-                        if !isEditing{
-                            finalText.mutableString.replaceOccurrences(of: "*", with: "", options: .literal, range: NSRange(location: startStar, length: endStar - startStar + countEmoji + 1))
-                        } else {
-                            finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(startStar + countEmoji...startStar + countEmoji))
-                            finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(endStar + countEmoji...endStar + countEmoji))
-                        }
-                        boolStar = false
-                        startStar = 0
+        //Underline
+        let textAfterItalic = finalText.string
+        let rangeUnderline = getRangeOfWordWithSign(sentence: textAfterItalic, sign: underlineSign)
+        if rangeUnderline.count > 0 {
+            var lastFirstRange = 0
+            var countRemoveUnderlineSign = 0
+            var continueCheckingUnderline = false
+            var totalEmoji = 0
+            for i in 0..<rangeUnderline.count {
+                if lastFirstRange == 0 {
+                    if (rangeUnderline[i].startIndex == 0 || checkCharBeforeAfter(char: textAfterItalic.substring(from: rangeUnderline[i].startIndex - 1, to: rangeUnderline[i].startIndex - 1))) {
+                        lastFirstRange = rangeUnderline[i].startIndex
+                        continueCheckingUnderline = true
                     } else {
-                        startStar = i
-                        startStar = startStar - (textUTF8.count - finalText.string.count)
+                        continueCheckingUnderline = false
                     }
                 }
-                
-                //ITALIC
-                if String(textUTF8.substring(from: i, to: i)) == "_" && !boolItalic {
-                    boolItalic = true
-                    startItalic = i
-                    startItalic = startItalic - (textUTF8.count - finalText.string.count)
-                } else if String(textUTF8.substring(from: i, to: i)) == "_" && boolItalic {
-                    endItalic = i
-                    endItalic = endItalic - (textUTF8.count - finalText.string.count)
-                    if (startItalic - 1 == -1 || checkCharBeforeAfter(char: String(finalText.string.substring(from: startItalic - 1, to: startItalic - 1)))) && (endItalic + 1 == finalText.string.count || checkCharBeforeAfter(char: String(finalText.string.substring(from: endItalic + 1, to: endItalic + 1)))) && endItalic - startItalic != 1 && !String(finalText.string.substring(from: startItalic + 1, to: endItalic - 1)).trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
-                        let countEmoji = finalText.string.countEmojiCharacter()
-                        finalText.addAttribute(.font, value: font.italic, range: NSRange(location: startItalic, length: endItalic - startItalic + (countEmoji + 1)))
-                        if !isEditing{
-                            finalText.mutableString.replaceOccurrences(of: "_", with: "", options: .literal, range: NSRange(location: startItalic, length: endItalic - startItalic + (countEmoji + 1)))
-                        } else {
-                            finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(startItalic + countEmoji...startItalic + countEmoji))
-                            finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(endItalic + countEmoji...endItalic + countEmoji))
-                        }
-                        boolItalic = false
-                        startItalic = 0
+                if !continueCheckingUnderline {
+                    continue
+                }
+                if (rangeUnderline[i].endIndex == textAfterItalic.count - 1 || checkCharBeforeAfter(char: textAfterItalic.substring(from: rangeUnderline[i].endIndex + 1, to: rangeUnderline[i].endIndex + 1))) {
+                    let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveUnderlineSign), to: rangeUnderline[i].endIndex - (2*countRemoveUnderlineSign)).countEmojiCharacter()
+                    totalEmoji = totalEmoji + countEmoji
+                    finalText.addAttribute(.underlineStyle, value: NSUnderlineStyle.thick.rawValue, range: NSRange(location: lastFirstRange - (2*countRemoveUnderlineSign), length: rangeUnderline[i].endIndex - lastFirstRange + totalEmoji + 1))
+                    if !isEditing{
+                        finalText.mutableString.replaceOccurrences(of: "\(underlineSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange - (2*countRemoveUnderlineSign), length: 1 + countEmoji))
+                        finalText.mutableString.replaceOccurrences(of: "\(underlineSign)", with: "", options: .literal, range: NSRange(location: rangeUnderline[i].endIndex - 1 - (2*countRemoveUnderlineSign) + countEmoji, length: 1 + countEmoji))
+                        countRemoveUnderlineSign += 1
                     } else {
-                        startItalic = i
-                        startItalic = startItalic - (textUTF8.count - finalText.string.count)
+                        finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + (totalEmoji == 0 ? 0 : totalEmoji - 1), length: 1))
+                        finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeUnderline[i].endIndex + totalEmoji, length: 1))
                     }
+                    lastFirstRange = 0
                 }
-                
-                //UNDERLINE
-                if String(textUTF8.substring(from: i, to: i)) == "^" && !boolUnderLine {
-                    boolUnderLine = true
-                    startUnderLine = i
-                    startUnderLine = startUnderLine - (textUTF8.count - finalText.string.count)
-                } else if String(textUTF8.substring(from: i, to: i)) == "^" && boolUnderLine {
-                    endUnderLine = i
-                    endUnderLine = endUnderLine - (textUTF8.count - finalText.string.count)
-                    if (startUnderLine - 1 == -1 || checkCharBeforeAfter(char: String(finalText.string.substring(from: startUnderLine - 1, to: startUnderLine - 1)))) && (endUnderLine + 1 == finalText.string.count || checkCharBeforeAfter(char: String(finalText.string.substring(from: endUnderLine + 1, to: endUnderLine + 1)))) && endUnderLine - startUnderLine != 1 && !String(finalText.string.substring(from: startUnderLine + 1, to: endUnderLine - 1)).trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
-                        let countEmoji = finalText.string.countEmojiCharacter()
-                        finalText.addAttribute(.underlineStyle, value: NSUnderlineStyle.thick.rawValue, range: NSRange(location: startUnderLine, length: endUnderLine - startUnderLine + (countEmoji + 1)))
-                        if !isEditing{
-                            finalText.mutableString.replaceOccurrences(of: "^", with: "", options: .literal, range: NSRange(location: startUnderLine, length: endUnderLine - startUnderLine + (countEmoji + 1)))
-                        } else {
-                            finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(startUnderLine + countEmoji...startUnderLine + countEmoji))
-                            finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(endUnderLine + countEmoji...endUnderLine + countEmoji))
-                        }
-                        boolUnderLine = false
-                        startUnderLine = 0
+            }
+        }
+        
+        //Strikethrough
+        let textAfterUnderline = finalText.string
+        let rangeStrikethrough = getRangeOfWordWithSign(sentence: textAfterUnderline, sign: strikethroughSign)
+        if rangeStrikethrough.count > 0 {
+            var lastFirstRange = 0
+            var countRemoveStrikethroughSign = 0
+            var continueCheckingStrikethrough = false
+            var totalEmoji = 0
+            for i in 0..<rangeStrikethrough.count {
+                if lastFirstRange == 0 {
+                    if (rangeStrikethrough[i].startIndex == 0 || checkCharBeforeAfter(char: textAfterUnderline.substring(from: rangeStrikethrough[i].startIndex - 1, to: rangeStrikethrough[i].startIndex - 1))) {
+                        lastFirstRange = rangeStrikethrough[i].startIndex
+                        continueCheckingStrikethrough = true
                     } else {
-                        startUnderLine = i
-                        startUnderLine = startUnderLine - (textUTF8.count - finalText.string.count)
+                        continueCheckingStrikethrough = false
                     }
                 }
-                
-                //STRIKETHROUGH
-                if String(textUTF8.substring(from: i, to: i)) == "~" && !boolStrike {
-                    boolStrike = true
-                    startStrike = i
-                    startStrike = startStrike - (textUTF8.count - finalText.string.count)
-                } else if String(textUTF8.substring(from: i, to: i)) == "~" && boolStrike {
-                    endStrike = i
-                    endStrike = endStrike - (textUTF8.count - finalText.string.count)
-                    if (startStrike - 1 == -1 || checkCharBeforeAfter(char: String(finalText.string.substring(from: startStrike - 1, to: startStrike - 1)))) && (endStrike + 1 == finalText.string.count || checkCharBeforeAfter(char: String(finalText.string.substring(from: endStrike + 1, to: endStrike + 1)))) && endStrike - startStrike != 1 && !String(finalText.string.substring(from: startStrike + 1, to: endStrike - 1)).trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
-                        let countEmoji = finalText.string.countEmojiCharacter()
-                        finalText.addAttribute(.strikethroughStyle, value: 2, range: NSRange(location: startStrike, length: endStrike - startStrike + (countEmoji + 1)))
-                        if !isEditing {
-                            finalText.mutableString.replaceOccurrences(of: "~", with: "", options: .literal, range: NSRange(location: startStrike, length: endStrike - startStrike + (countEmoji + 1)))
-                        } else {
-                            finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(startStrike + countEmoji...startStrike + countEmoji))
-                            finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(endStrike + countEmoji...endStrike + countEmoji))
-                        }
-                        boolStrike = false
-                        startStrike = 0
+                if !continueCheckingStrikethrough {
+                    continue
+                }
+                if (rangeStrikethrough[i].endIndex == textAfterUnderline.count - 1 || checkCharBeforeAfter(char: textAfterUnderline.substring(from: rangeStrikethrough[i].endIndex + 1, to: rangeStrikethrough[i].endIndex + 1))) {
+                    let countEmoji = finalText.string.substring(from: lastFirstRange - (2*countRemoveStrikethroughSign), to: rangeStrikethrough[i].endIndex - (2*countRemoveStrikethroughSign)).countEmojiCharacter()
+                    totalEmoji = totalEmoji + countEmoji
+                    finalText.addAttribute(.strikethroughStyle, value: 2, range: NSRange(location: lastFirstRange - (2*countRemoveStrikethroughSign), length: rangeStrikethrough[i].endIndex - lastFirstRange + totalEmoji + 1))
+                    if !isEditing{
+                        finalText.mutableString.replaceOccurrences(of: "\(strikethroughSign)", with: "", options: .literal, range: NSRange(location: lastFirstRange - (2*countRemoveStrikethroughSign), length: 1 + countEmoji))
+                        finalText.mutableString.replaceOccurrences(of: "\(strikethroughSign)", with: "", options: .literal, range: NSRange(location: rangeStrikethrough[i].endIndex - 1 - (2*countRemoveStrikethroughSign) + countEmoji, length: 1 + countEmoji))
+                        countRemoveStrikethroughSign += 1
                     } else {
-                        startStrike = i
-                        startStrike = startStrike - (textUTF8.count - finalText.string.count)
+                        finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: lastFirstRange + (totalEmoji == 0 ? 0 : totalEmoji - 1), length: 1))
+                        finalText.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: rangeStrikethrough[i].endIndex + totalEmoji, length: 1))
                     }
+                    lastFirstRange = 0
                 }
             }
-            if !isEditing {
-                let listTextEnter = finalText.string.split(separator: "\n")
-                for j in 0...listTextEnter.count - 1 {
-                    let listText = listTextEnter[j].split(separator: " ")
-                    for i in 0...listText.count - 1 {
-                        if listText[i].lowercased().checkStartWithLink() {
-                            if ((listText[i].lowercased().starts(with: "www.") && listText[i].lowercased().split(separator: ".").count >= 3) || (!listText[i].lowercased().starts(with: "www.") && listText[i].lowercased().split(separator: ".").count >= 2)) && listText[i].lowercased().split(separator: ".").last!.count >= 2 {
-                                if let range: Range<String.Index> = finalText.string.range(of: listText[i]) {
-                                    let index: Int = finalText.string.distance(from: finalText.string.startIndex, to: range.lowerBound)
-                                    finalText.addAttribute(.foregroundColor, value: UIColor.linkColor, range: NSRange(index...index + listText[i].count - 1))
-                                    finalText.addAttribute(.underlineStyle, value: NSUnderlineStyle.thick.rawValue, range: NSRange(index...index + listText[i].count - 1))
-                                }
+        }
+        
+        if !isEditing {
+            let listTextEnter = finalText.string.split(separator: "\n")
+            for j in 0...listTextEnter.count - 1 {
+                let listText = listTextEnter[j].split(separator: " ")
+                for i in 0...listText.count - 1 {
+                    if listText[i].lowercased().checkStartWithLink() {
+                        if ((listText[i].lowercased().starts(with: "www.") && listText[i].lowercased().split(separator: ".").count >= 3) || (!listText[i].lowercased().starts(with: "www.") && listText[i].lowercased().split(separator: ".").count >= 2)) && listText[i].lowercased().split(separator: ".").last!.count >= 2 {
+                            if let range: Range<String.Index> = finalText.string.range(of: listText[i]) {
+                                let index: Int = finalText.string.distance(from: finalText.string.startIndex, to: range.lowerBound)
+                                finalText.addAttribute(.foregroundColor, value: UIColor.linkColor, range: NSRange(index...index + listText[i].count - 1))
+                                finalText.addAttribute(.underlineStyle, value: NSUnderlineStyle.thick.rawValue, range: NSRange(index...index + listText[i].count - 1))
                             }
                         }
                     }
                 }
             }
-            if isSearching {
-                let range = NSString(string: finalText.string).range(of: textSearch, options: .caseInsensitive) // 2
-                let highlightColor = UIColor.systemYellow // 3
-                let highlightedAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.backgroundColor: highlightColor] // 4
-                
-                finalText.addAttributes(highlightedAttributes, range: range) // 5
-            }
+        }
+        if isSearching {
+            let range = NSString(string: finalText.string).range(of: textSearch, options: .caseInsensitive) // 2
+            let highlightColor = UIColor.systemYellow // 3
+            let highlightedAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.backgroundColor: highlightColor] // 4
+            
+            finalText.addAttributes(highlightedAttributes, range: range) // 5
         }
         
         return finalText
@@ -796,6 +821,30 @@ extension String {
         //|| self.starts(with: "*https://") || self.starts(with: "*http://") || self.starts(with: "*www.") || self.starts(with: "_https://") || self.starts(with: "_http://") || self.starts(with: "_www.") || self.starts(with: "^https://") || self.starts(with: "^http://") || self.starts(with: "^www.") || self.starts(with: "~https://") || self.starts(with: "~http://") || self.starts(with: "~www.")
     }
     
+    func getRangeOfWordWithSign(sentence: String, sign: Character) -> [Range<Int>] {
+        let asterisk: Character = sign
+        var ranges = [Range<Int>]()
+        
+        var startIndex = sentence.startIndex
+        
+        while let startRange = sentence[startIndex...].firstIndex(of: asterisk),
+              let endRange = sentence[startRange...].dropFirst().firstIndex(of: asterisk) {
+            
+            let range = startRange..<endRange
+            let word = sentence[range].replacingOccurrences(of: "\(sign)", with: "")
+            
+            if !word.isEmpty {
+                let lower = sentence.distance(from: sentence.startIndex, to: startRange)
+                let upper = sentence.distance(from: sentence.startIndex, to: endRange)
+                ranges.append(Range(uncheckedBounds: (lower: lower, upper: upper)))
+            }
+            
+            startIndex = endRange
+        }
+        
+        return ranges
+    }
+    
 }
 
 extension UIFont {