Compare commits
No commits in common. "62408fc4bda6c1928329e647f73fdbdbe11d43eb" and "1d169bec6745dd6218b303883195eb3fe057d854" have entirely different histories.
62408fc4bd
...
1d169bec67
|
@ -104,7 +104,6 @@
|
||||||
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; };
|
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; };
|
||||||
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */; };
|
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */; };
|
||||||
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2425217ABF63005076CC /* UserActivityType.swift */; };
|
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2425217ABF63005076CC /* UserActivityType.swift */; };
|
||||||
D62FF04823D7CDD700909D6E /* AttributedStringHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */; };
|
|
||||||
D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Helpers.swift */; };
|
D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Helpers.swift */; };
|
||||||
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B762138D94E00CE884A /* ComposeMediaView.swift */; };
|
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B762138D94E00CE884A /* ComposeMediaView.swift */; };
|
||||||
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; };
|
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; };
|
||||||
|
@ -380,7 +379,6 @@
|
||||||
D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; };
|
D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; };
|
||||||
D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+Extensions.swift"; sourceTree = "<group>"; };
|
D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D62D2425217ABF63005076CC /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = "<group>"; };
|
D62D2425217ABF63005076CC /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = "<group>"; };
|
||||||
D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringHelperTests.swift; sourceTree = "<group>"; };
|
|
||||||
D6333B362137838300CE884A /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = "<group>"; };
|
D6333B362137838300CE884A /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = "<group>"; };
|
||||||
D6333B762138D94E00CE884A /* ComposeMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeMediaView.swift; sourceTree = "<group>"; };
|
D6333B762138D94E00CE884A /* ComposeMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeMediaView.swift; sourceTree = "<group>"; };
|
||||||
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
|
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -1217,7 +1215,6 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D6D4DDE4212518A200E1C4BB /* TuskerTests.swift */,
|
D6D4DDE4212518A200E1C4BB /* TuskerTests.swift */,
|
||||||
D62FF04723D7CDD700909D6E /* AttributedStringHelperTests.swift */,
|
|
||||||
D6D4DDE6212518A200E1C4BB /* Info.plist */,
|
D6D4DDE6212518A200E1C4BB /* Info.plist */,
|
||||||
);
|
);
|
||||||
path = TuskerTests;
|
path = TuskerTests;
|
||||||
|
@ -1758,7 +1755,6 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D62FF04823D7CDD700909D6E /* AttributedStringHelperTests.swift in Sources */,
|
|
||||||
D6D4DDE5212518A200E1C4BB /* TuskerTests.swift in Sources */,
|
D6D4DDE5212518A200E1C4BB /* TuskerTests.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
|
@ -8,95 +8,28 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
private let ASCII_NEWLINE: unichar = 10
|
extension NSMutableAttributedString {
|
||||||
private let ASCII_SPACE: unichar = 32
|
|
||||||
|
|
||||||
extension NSAttributedString {
|
|
||||||
|
|
||||||
var fullRange: NSRange {
|
var fullRange: NSRange {
|
||||||
return NSRange(location: 0, length: self.length)
|
return NSRange(location: 0, length: self.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new string with the whitespace collapsed according to the CSS Text Module Level 3 rules.
|
|
||||||
/// See https://www.w3.org/TR/css-text-3/#white-space-phase-1
|
|
||||||
func collapsingWhitespace() -> NSAttributedString {
|
|
||||||
let mut = NSMutableAttributedString(attributedString: self)
|
|
||||||
mut.collapseWhitespace()
|
|
||||||
return mut
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NSMutableAttributedString {
|
|
||||||
|
|
||||||
func trimLeadingCharactersInSet(_ charSet: CharacterSet) {
|
func trimLeadingCharactersInSet(_ charSet: CharacterSet) {
|
||||||
var range = (string as NSString).rangeOfCharacter(from: charSet)
|
var range = (string as NSString).rangeOfCharacter(from: charSet)
|
||||||
|
|
||||||
while range.length != 0 && range.location == 0 {
|
while range.length != 0 && range.location == 0 {
|
||||||
replaceCharacters(in: range, with: "")
|
replaceCharacters(in: range, with: "")
|
||||||
range = (string as NSString).rangeOfCharacter(from: charSet)
|
range = (string as NSString).rangeOfCharacter(from: charSet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func trimTrailingCharactersInSet(_ charSet: CharacterSet) {
|
func trimTrailingCharactersInSet(_ charSet: CharacterSet) {
|
||||||
var range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)
|
var range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)
|
||||||
|
|
||||||
while range.length != 0 && range.length + range.location == length {
|
while range.length != 0 && range.length + range.location == length {
|
||||||
replaceCharacters(in: range, with: "")
|
replaceCharacters(in: range, with: "")
|
||||||
range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)
|
range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collapses whitespace in this string according to the CSS Text Module Level 3 rules.
|
|
||||||
/// See https://www.w3.org/TR/css-text-3/#white-space-phase-1
|
|
||||||
func collapseWhitespace() {
|
|
||||||
let str = self.mutableString
|
|
||||||
|
|
||||||
var i = 0
|
|
||||||
while i < str.length {
|
|
||||||
if str.character(at: i) == ASCII_NEWLINE {
|
|
||||||
var j: Int
|
|
||||||
if i > 0 {
|
|
||||||
// scan backwards to find beginning of space characters preceeding newline
|
|
||||||
j = i - 1
|
|
||||||
while j >= 0 {
|
|
||||||
if str.character(at: j) != ASCII_SPACE {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
j -= 1
|
|
||||||
}
|
|
||||||
// add one after loop completes because start of range is _inclusive_
|
|
||||||
j += 1
|
|
||||||
} else {
|
|
||||||
j = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var k: Int
|
|
||||||
if i < str.length - 1 {
|
|
||||||
// scan forwards to find end of space characters following newline
|
|
||||||
k = i + 1
|
|
||||||
while k < str.length {
|
|
||||||
if str.character(at: k) != ASCII_SPACE {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
k += 1
|
|
||||||
}
|
|
||||||
// don't need to subtract one before breaking out of loop, because end of range is _exclusive_
|
|
||||||
} else {
|
|
||||||
// range end is _exclusive_, so use whole string length that way last character is included
|
|
||||||
k = str.length
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there's only one character to be replaced, that means we'd be replacing the newline with a newline, so don't bother
|
|
||||||
if k - j > 1 {
|
|
||||||
str.replaceCharacters(in: NSRange(location: j, length: k - j), with: "\n")
|
|
||||||
|
|
||||||
// continue scanning through the string starting after the newline we just inserted
|
|
||||||
i = j
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,12 +110,11 @@ class ContentTextView: LinkTextView {
|
||||||
let attributedText = attributedTextForHTMLNode(body)
|
let attributedText = attributedTextForHTMLNode(body)
|
||||||
let mutAttrString = NSMutableAttributedString(attributedString: attributedText)
|
let mutAttrString = NSMutableAttributedString(attributedString: attributedText)
|
||||||
mutAttrString.trimTrailingCharactersInSet(.whitespacesAndNewlines)
|
mutAttrString.trimTrailingCharactersInSet(.whitespacesAndNewlines)
|
||||||
mutAttrString.collapseWhitespace()
|
|
||||||
|
|
||||||
self.attributedText = mutAttrString
|
self.attributedText = mutAttrString
|
||||||
}
|
}
|
||||||
|
|
||||||
private func attributedTextForHTMLNode(_ node: Node, usePreformattedText: Bool = false) -> NSAttributedString {
|
func attributedTextForHTMLNode(_ node: Node, usePreformattedText: Bool = false) -> NSAttributedString {
|
||||||
switch node {
|
switch node {
|
||||||
case let node as TextNode:
|
case let node as TextNode:
|
||||||
let text: String
|
let text: String
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
//
|
|
||||||
// AttributedStringHelperTests.swift
|
|
||||||
// TuskerTests
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 1/21/20.
|
|
||||||
// Copyright © 2020 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import XCTest
|
|
||||||
@testable import Tusker
|
|
||||||
|
|
||||||
class AttributedStringHelperTests: XCTestCase {
|
|
||||||
|
|
||||||
override func setUp() {
|
|
||||||
}
|
|
||||||
|
|
||||||
override func tearDown() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCollapsingWhitespace() {
|
|
||||||
var str = NSAttributedString(string: "test 1\n")
|
|
||||||
XCTAssertEqual(str.collapsingWhitespace(), NSAttributedString(string: "test 1\n"))
|
|
||||||
|
|
||||||
str = NSAttributedString(string: "test 2 \n")
|
|
||||||
XCTAssertEqual(str.collapsingWhitespace(), NSAttributedString(string: "test 2\n"))
|
|
||||||
|
|
||||||
str = NSAttributedString(string: "test 3\n ")
|
|
||||||
XCTAssertEqual(str.collapsingWhitespace(), NSAttributedString(string: "test 3\n"))
|
|
||||||
|
|
||||||
str = NSAttributedString(string: "test 4 \n ")
|
|
||||||
XCTAssertEqual(str.collapsingWhitespace(), NSAttributedString(string: "test 4\n"))
|
|
||||||
|
|
||||||
str = NSAttributedString(string: "test 5 \n blah")
|
|
||||||
XCTAssertEqual(str.collapsingWhitespace(), NSAttributedString(string: "test 5\nblah"))
|
|
||||||
|
|
||||||
str = NSAttributedString(string: "\ntest 6")
|
|
||||||
XCTAssertEqual(str.collapsingWhitespace(), NSAttributedString(string: "\ntest 6"))
|
|
||||||
|
|
||||||
str = NSAttributedString(string: " \ntest 7")
|
|
||||||
XCTAssertEqual(str.collapsingWhitespace(), NSAttributedString(string: "\ntest 7"))
|
|
||||||
|
|
||||||
str = NSAttributedString(string: " \n test 8")
|
|
||||||
XCTAssertEqual(str.collapsingWhitespace(), NSAttributedString(string: "\ntest 8"))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue