Skip to content

Commit 9b65f8f

Browse files
authoredMar 20, 2025··
Cleanup String+Extensions in Share app extension (#24264)
* Cleanup String+Extensions in Share app extension * Add missing method * Move remaining methods
1 parent 18bd13f commit 9b65f8f

File tree

5 files changed

+130
-157
lines changed

5 files changed

+130
-157
lines changed
 

‎Modules/Sources/WordPressShared/Utility/String+Helpers.swift

+94
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,98 @@ extension String {
216216
let prefix = self.prefix(limit - 1)
217217
return "\(prefix)"
218218
}
219+
220+
public func arrayOfTags() -> [String] {
221+
guard !self.isEmpty else {
222+
return [String()]
223+
}
224+
225+
return self.components(separatedBy: ",").map({ $0.trimmingCharacters(in: .whitespacesAndNewlines) })
226+
}
227+
228+
/// Returns a Boolean value indicating if this String begins with the provided prefix.
229+
/// - Parameter prefix: The prefix to check for.
230+
/// - Parameter options: The string comparison options to use when checking for the prefix.
231+
public func hasPrefix(_ prefix: String, with options: CompareOptions) -> Bool {
232+
let fullOptions = options.union([.anchored])
233+
return range(of: prefix, options: fullOptions) != nil
234+
}
235+
}
236+
237+
extension String {
238+
/// Returns a String with <A>nchored links
239+
///
240+
public func stringWithAnchoredLinks() -> String {
241+
guard let output = (self as NSString).mutableCopy() as? NSMutableString,
242+
let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else {
243+
return self
244+
}
245+
246+
let range = NSMakeRange(0, count)
247+
var offset = 0
248+
249+
detector.enumerateMatches(in: self, options: [], range: range) { (result, flags, stop) in
250+
guard let range = result?.range else {
251+
return
252+
}
253+
254+
let rangeWithOffset = NSMakeRange(range.location + offset, range.length)
255+
let rawURL = output.substring(with: rangeWithOffset)
256+
257+
var niceURL: String
258+
if let urlComps = URLComponents(string: rawURL), let host = urlComps.host {
259+
niceURL = "\(host)\(urlComps.path)"
260+
} else {
261+
niceURL = rawURL
262+
}
263+
264+
let anchoredURL = "<a href=\"\(rawURL)\">\(niceURL)</a>"
265+
266+
output.replaceCharacters(in: rangeWithOffset, with: anchoredURL)
267+
offset += anchoredURL.count - rawURL.count
268+
}
269+
270+
return output as String
271+
}
272+
273+
/// Creates a WP friendly <img> string based on the provided parameters
274+
///
275+
/// NOTE: Height and width must both be provided in order for them to be inserted into the returned string.
276+
///
277+
/// - Parameters:
278+
/// - mediaURL: Complete URL string to the remote image
279+
/// - uploadID: Upload ID for the image
280+
/// - remoteID: Remote image ID
281+
/// - height: Height of image. Can be nil unless width is provided
282+
/// - width: Width of image. Can be nil unless height is provided
283+
/// - Returns: <img> element appended to the current string otherwise the current string if the mediaURL param is nil or empty
284+
///
285+
public func stringByAppendingMediaURL(mediaURL: String?,
286+
uploadID: String? = nil,
287+
remoteID: Int64? = nil,
288+
height: Int32? = nil,
289+
width: Int32? = nil) -> String {
290+
guard let mediaURL, !mediaURL.isEmpty else {
291+
return self
292+
}
293+
294+
var returnURLString = "<img"
295+
296+
if let remoteID, remoteID > 0 {
297+
returnURLString.append(contentsOf: " wp-image-\(remoteID)")
298+
}
299+
returnURLString.append(contentsOf: " src='\(mediaURL)' class='size-full'")
300+
301+
if let uploadID {
302+
returnURLString.append(contentsOf: " data-wp_upload_id='\(uploadID)'")
303+
}
304+
305+
if let height, height > 0,
306+
let width, width > 0 {
307+
returnURLString.append(contentsOf: " width='\(width)' height='\(height)'")
308+
}
309+
returnURLString.append(contentsOf: " />")
310+
311+
return self + returnURLString
312+
}
219313
}

‎Modules/Tests/WordPressSharedTests/StringHelperTests.swift

+36
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,42 @@ class StringHelperTests: XCTestCase {
1414
super.tearDown()
1515
}
1616

17+
// Note:
18+
// Specially extra aligned for my RWC friends. With love.
19+
//
20+
let links = ["http://www.google.com", "http://www.automattic.com", "http://wordpress.com?some=random", "http://wordpress.com/path/to/nowhere", "http://wordpress.com/", "https://www.wordpress.blog"]
21+
let linkText = ["www.google.com", "www.automattic.com", "wordpress.com", "wordpress.com/path/to/nowhere", "wordpress.com/", "www.wordpress.blog"]
22+
23+
let text = " Lorem Ipsum Matarem Les Idiotum Sarasum Zorrentum Modus Operandum "
24+
let anchor = "<a href=\"%@\">%@</a>"
25+
26+
func testLinkifyingPlainLinks() {
27+
var count = 0
28+
for link in links {
29+
let linkified = String(format: anchor, link, linkText[count])
30+
XCTAssertEqual(link.stringWithAnchoredLinks(), linkified, "Oh noes!")
31+
count += 1
32+
}
33+
}
34+
35+
func testLinkifyingLinksWithinText() {
36+
var plain = String()
37+
var linkified = String()
38+
39+
var count = 0
40+
for link in links {
41+
plain += text + link
42+
linkified += text + String(format: anchor, link, linkText[count])
43+
count += 1
44+
}
45+
46+
XCTAssertEqual(plain.stringWithAnchoredLinks(), linkified, "Oh noes!")
47+
}
48+
49+
func testLinkifyingPlainText() {
50+
XCTAssertEqual(text.stringWithAnchoredLinks(), text, "Oh noes!")
51+
}
52+
1753
func testTrim() {
1854
let trimmedString = "string string"
1955
let sourceString = " \(trimmedString) "

‎WordPress/WordPress.xcodeproj/project.pbxproj

-18
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,6 @@
684684
74021A01202E12F4006CC39F /* SharedCoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 746D6B241FBF701F003C45BE /* SharedCoreDataStack.swift */; };
685685
74021A02202E12FF006CC39F /* Extensions.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 74FA4BE31FBFA0660031EAAD /* Extensions.xcdatamodeld */; };
686686
74021A03202E1307006CC39F /* NSExtensionContext+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7D1CD101A600B26DF6 /* NSExtensionContext+Extensions.swift */; };
687-
74021A04202E1307006CC39F /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */; };
688687
74021A05202E1307006CC39F /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5FA868A1D10A41600AB5F7E /* UIImage+Extensions.swift */; };
689688
74021A07202E1307006CC39F /* UINavigationController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74AC1DA0200D0CC300973CAD /* UINavigationController+Extensions.swift */; };
690689
74021A09202E1323006CC39F /* ShareSegueHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745EAF442003FD050066F415 /* ShareSegueHandler.swift */; };
@@ -826,7 +825,6 @@
826825
809620FB28E540D700940A5D /* RemoteBlog+Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE39E17120CB117B00CABA05 /* RemoteBlog+Capabilities.swift */; };
827826
809620FC28E540D700940A5D /* ShareModularViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6787F41FFF2886005D9F01 /* ShareModularViewController.swift */; };
828827
809620FD28E540D700940A5D /* NSExtensionContext+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7D1CD101A600B26DF6 /* NSExtensionContext+Extensions.swift */; };
829-
809620FE28E540D700940A5D /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */; };
830828
8096210028E540D700940A5D /* UINavigationController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74AC1DA0200D0CC300973CAD /* UINavigationController+Extensions.swift */; };
831829
8096210128E540D700940A5D /* PostUploadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74AF4D711FE417D200E3EBFE /* PostUploadOperation.swift */; };
832830
8096210628E540D700940A5D /* Tracks+ShareExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B504F5F41C9C2BD000F8B1C6 /* Tracks+ShareExtension.swift */; };
@@ -845,7 +843,6 @@
845843
8096213E28E55C9400940A5D /* NSExtensionContext+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7D1CD101A600B26DF6 /* NSExtensionContext+Extensions.swift */; };
846844
8096214028E55C9400940A5D /* Extensions.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 74FA4BE31FBFA0660031EAAD /* Extensions.xcdatamodeld */; };
847845
8096214228E55C9400940A5D /* PostUploadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74AF4D711FE417D200E3EBFE /* PostUploadOperation.swift */; };
848-
8096214528E55C9400940A5D /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */; };
849846
8096214828E55C9400940A5D /* ShareExtensionAbstractViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745EAF462003FDAA0066F415 /* ShareExtensionAbstractViewController.swift */; };
850847
8096214928E55C9400940A5D /* ExtensionPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74402F29200528F200A1D4A2 /* ExtensionPresentationController.swift */; };
851848
8096214A28E55C9400940A5D /* SharePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = E125F1E31E8E595E00320B67 /* SharePost.swift */; };
@@ -985,9 +982,6 @@
985982
B532ACD31DC3AE1200FFFA57 /* OHHTTPStubs+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B532ACD21DC3AE1200FFFA57 /* OHHTTPStubs+Helpers.swift */; };
986983
B5416CFE1C1756B900006DD8 /* PushNotificationsManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B5416CFD1C1756B900006DD8 /* PushNotificationsManagerTests.m */; };
987984
B5552D7E1CD101A600B26DF6 /* NSExtensionContext+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7D1CD101A600B26DF6 /* NSExtensionContext+Extensions.swift */; };
988-
B5552D801CD1028C00B26DF6 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */; };
989-
B5552D821CD1061F00B26DF6 /* StringExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D811CD1061F00B26DF6 /* StringExtensionsTests.swift */; };
990-
B5552D831CD1062400B26DF6 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */; };
991985
B556EFCB1DCA374200728F93 /* DictionaryHelpersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B556EFCA1DCA374200728F93 /* DictionaryHelpersTests.swift */; };
992986
B55F1AA21C107CE200FD04D4 /* BlogSettingsDiscussionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55F1AA11C107CE200FD04D4 /* BlogSettingsDiscussionTests.swift */; };
993987
B566EC751B83867800278395 /* NSMutableAttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566EC741B83867800278395 /* NSMutableAttributedStringTests.swift */; };
@@ -1404,7 +1398,6 @@
14041398
FABB23A32602FC2C00C8785C /* Sites.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 3F46AB0225BF5D6300CE2E98 /* Sites.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; };
14051399
FABB23E62602FC2C00C8785C /* ShareMediaFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7430C4481F97F23600E2673E /* ShareMediaFileManager.swift */; };
14061400
FABB24062602FC2C00C8785C /* UploadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741E22441FC0CC55007967AB /* UploadOperation.swift */; };
1407-
FABB24702602FC2C00C8785C /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */; };
14081401
FABB24EF2602FC2C00C8785C /* ShareNoticeConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74EA3B87202A0462004F802D /* ShareNoticeConstants.swift */; };
14091402
FABB254A2602FC2C00C8785C /* SharePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = E125F1E31E8E595E00320B67 /* SharePost.swift */; };
14101403
FABB26202602FC2C00C8785C /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E21C760202BBC8D00837CF5 /* iAd.framework */; };
@@ -2711,8 +2704,6 @@
27112704
B532ACD21DC3AE1200FFFA57 /* OHHTTPStubs+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OHHTTPStubs+Helpers.swift"; sourceTree = "<group>"; };
27122705
B5416CFD1C1756B900006DD8 /* PushNotificationsManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PushNotificationsManagerTests.m; sourceTree = "<group>"; };
27132706
B5552D7D1CD101A600B26DF6 /* NSExtensionContext+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSExtensionContext+Extensions.swift"; path = "WordPressShareExtension/NSExtensionContext+Extensions.swift"; sourceTree = SOURCE_ROOT; };
2714-
B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "String+Extensions.swift"; path = "WordPressShareExtension/String+Extensions.swift"; sourceTree = SOURCE_ROOT; };
2715-
B5552D811CD1061F00B26DF6 /* StringExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensionsTests.swift; sourceTree = "<group>"; };
27162707
B556EFCA1DCA374200728F93 /* DictionaryHelpersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryHelpersTests.swift; sourceTree = "<group>"; };
27172708
B55F1AA11C107CE200FD04D4 /* BlogSettingsDiscussionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlogSettingsDiscussionTests.swift; sourceTree = "<group>"; };
27182709
B566EC741B83867800278395 /* NSMutableAttributedStringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSMutableAttributedStringTests.swift; sourceTree = "<group>"; };
@@ -5824,7 +5815,6 @@
58245815
isa = PBXGroup;
58255816
children = (
58265817
B5552D7D1CD101A600B26DF6 /* NSExtensionContext+Extensions.swift */,
5827-
B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */,
58285818
B5FA868A1D10A41600AB5F7E /* UIImage+Extensions.swift */,
58295819
74AC1DA0200D0CC300973CAD /* UINavigationController+Extensions.swift */,
58305820
74BC35B720499EEB00AC1525 /* RemotePostCategory+Extensions.swift */,
@@ -6427,7 +6417,6 @@
64276417
children = (
64286418
B556EFCA1DCA374200728F93 /* DictionaryHelpersTests.swift */,
64296419
E1C9AA551C10427100732665 /* MathTest.swift */,
6430-
B5552D811CD1061F00B26DF6 /* StringExtensionsTests.swift */,
64316420
E1AB5A081E0BF31E00574B4E /* ArrayTests.swift */,
64326421
0885A3661E837AFE00619B4D /* URLIncrementalFilenameTests.swift */,
64336422
D88A649D208D82D2008AE9BC /* XCTestCase+Wait.swift */,
@@ -8625,7 +8614,6 @@
86258614
7492F78E1F9BD94500B5A04A /* ShareMediaFileManager.swift in Sources */,
86268615
741E22461FC0CC55007967AB /* UploadOperation.swift in Sources */,
86278616
F4D8296A2931083000038726 /* MigrationSuccessCell+WordPress.swift in Sources */,
8628-
B5552D831CD1062400B26DF6 /* String+Extensions.swift in Sources */,
86298617
74EA3B88202A0462004F802D /* ShareNoticeConstants.swift in Sources */,
86308618
83E1E5592A58B5C2000B576F /* JetpackSocialError.swift in Sources */,
86318619
E125F1E41E8E595E00320B67 /* SharePost.swift in Sources */,
@@ -8857,7 +8845,6 @@
88578845
74021A03202E1307006CC39F /* NSExtensionContext+Extensions.swift in Sources */,
88588846
74021A02202E12FF006CC39F /* Extensions.xcdatamodeld in Sources */,
88598847
740219FF202E12F4006CC39F /* PostUploadOperation.swift in Sources */,
8860-
74021A04202E1307006CC39F /* String+Extensions.swift in Sources */,
88618848
74021A13202E1383006CC39F /* ShareExtensionAbstractViewController.swift in Sources */,
88628849
74021A10202E1370006CC39F /* ExtensionPresentationController.swift in Sources */,
88638850
74021A17202E13C6006CC39F /* SharePost.swift in Sources */,
@@ -8915,7 +8902,6 @@
89158902
809620FB28E540D700940A5D /* RemoteBlog+Capabilities.swift in Sources */,
89168903
809620FC28E540D700940A5D /* ShareModularViewController.swift in Sources */,
89178904
809620FD28E540D700940A5D /* NSExtensionContext+Extensions.swift in Sources */,
8918-
809620FE28E540D700940A5D /* String+Extensions.swift in Sources */,
89198905
8096210028E540D700940A5D /* UINavigationController+Extensions.swift in Sources */,
89208906
8096210128E540D700940A5D /* PostUploadOperation.swift in Sources */,
89218907
8096210628E540D700940A5D /* Tracks+ShareExtension.swift in Sources */,
@@ -8938,7 +8924,6 @@
89388924
8096213E28E55C9400940A5D /* NSExtensionContext+Extensions.swift in Sources */,
89398925
8096214028E55C9400940A5D /* Extensions.xcdatamodeld in Sources */,
89408926
8096214228E55C9400940A5D /* PostUploadOperation.swift in Sources */,
8941-
8096214528E55C9400940A5D /* String+Extensions.swift in Sources */,
89428927
8096214828E55C9400940A5D /* ShareExtensionAbstractViewController.swift in Sources */,
89438928
8096214928E55C9400940A5D /* ExtensionPresentationController.swift in Sources */,
89448929
8096214A28E55C9400940A5D /* SharePost.swift in Sources */,
@@ -9026,7 +9011,6 @@
90269011
CE39E17220CB117B00CABA05 /* RemoteBlog+Capabilities.swift in Sources */,
90279012
BE6787F51FFF2886005D9F01 /* ShareModularViewController.swift in Sources */,
90289013
B5552D7E1CD101A600B26DF6 /* NSExtensionContext+Extensions.swift in Sources */,
9029-
B5552D801CD1028C00B26DF6 /* String+Extensions.swift in Sources */,
90309014
74AC1DA1200D0CC300973CAD /* UINavigationController+Extensions.swift in Sources */,
90319015
74AF4D7D1FE417D200E3EBFE /* PostUploadOperation.swift in Sources */,
90329016
B504F5F51C9C2BD000F8B1C6 /* Tracks+ShareExtension.swift in Sources */,
@@ -9272,7 +9256,6 @@
92729256
DCF892D0282FA42A00BB71E1 /* SiteStatsImmuTableRowsTests.swift in Sources */,
92739257
93EF094C19ED533500C89770 /* ContextManagerTests.swift in Sources */,
92749258
F17A2A2023BFBD84001E96AC /* UIView+ExistingConstraints.swift in Sources */,
9275-
B5552D821CD1061F00B26DF6 /* StringExtensionsTests.swift in Sources */,
92769259
3F759FBA2A2DA93B0039A845 /* WPAccount+Fixture.swift in Sources */,
92779260
77A141172B68546100BF75DD /* BooleanUserDefaultsDebugViewModelTests.swift in Sources */,
92789261
73178C3521BEE9AC00E37C9A /* TitleSubtitleHeaderTests.swift in Sources */,
@@ -9489,7 +9472,6 @@
94899472
F4D829642930EA4C00038726 /* MigrationDeleteWordPressViewModel.swift in Sources */,
94909473
3FF717FF291F07AB00323614 /* MigrationCenterViewConfiguration.swift in Sources */,
94919474
3FFDEF882918596B00B625CE /* MigrationDoneViewModel.swift in Sources */,
9492-
FABB24702602FC2C00C8785C /* String+Extensions.swift in Sources */,
94939475
FAADE42626159AFE00BF29FE /* AppConstants.swift in Sources */,
94949476
3FF15A56291B4EEA00E1B4E5 /* MigrationCenterView.swift in Sources */,
94959477
F49B9A08293A21F4000CEFCE /* MigrationEvent.swift in Sources */,

‎WordPress/WordPressShareExtension/String+Extensions.swift

-98
This file was deleted.

‎WordPress/WordPressTest/Extensions/StringExtensionsTests.swift

-41
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.