Ind.ie is now Small Technology Foundation.
Helpers.swift 6.26 KB
Newer Older
Aral Balkan's avatar
Aral Balkan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
//
//  File.swift
//  Heartbeat
//
//  Created by Aral Balkan on 25/09/2014.
//  Copyright (c) 2014 ind.ie. All rights reserved.
//

import Foundation

//
// Helpers
//

15
//
16
// MARK: - Accessibility
17 18 19 20
//

func makeAccessibilityAnnouncement(message:String)
{
21 22 23 24
    //
    // Note: Documentation on NSAccessibilityAnnouncementRequestedNotification is wrong. Correct usage, via NSAccessibility.h: “This notification should be posted for the application element.”
    // (Also see http://lists.apple.com/archives/accessibility-dev/2013/Jul/msg00027.html and rdar://14543376 )
    //
25
    NSAccessibilityPostNotificationWithUserInfo(NSApp.mainWindow, NSAccessibilityAnnouncementRequestedNotification, [NSAccessibilityAnnouncementKey: message, NSAccessibilityPriorityKey: NSAccessibilityPriorityLevel.High.rawValue])
26 27
}

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
//
// MARK: NSTableView
//

//
// Seriously, how often is it that all you want to do is to select a darn row? :)
//
extension NSTableView
{
    func selectRow(row:Int)
    {
        self.selectRowIndexes(NSIndexSet(index: row), byExtendingSelection: false)
    }
}

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
//
// MARK: - Date
//

var globalISO8601DateFormatter:ISO8601DateFormatter?

//
// Returns a current timestamp (UTC) in our standard ISO8601-based string format.
//
func ISO8601DateString() -> String
{
    if globalISO8601DateFormatter == nil
    {
        // Set up the ISO 8601 date formatter.
        globalISO8601DateFormatter = ISO8601DateFormatter()
        globalISO8601DateFormatter!.format = .Calendar
        globalISO8601DateFormatter!.includeTime = true
        globalISO8601DateFormatter!.useMillisecondPrecision = true
        globalISO8601DateFormatter!.timeSeparator = ("_" as NSString).characterAtIndex(0)
    }
    
    return globalISO8601DateFormatter!.stringFromDate(NSDate(), timeZone: NSTimeZone(abbreviation: "UTC"))
}
66

67 68 69 70
//
// Other
//

71

72
//
73
// Allows graceful overriding of any NSResponder subclass’s initialisation
74 75
// using a common initialiser.
//
76 77 78 79 80
// MARK: - Extension
extension NSResponder
{
    enum InitMethod
    {
81 82 83 84
        case Default
        case Coder(NSCoder)
    }
}
85 86 87 88 89

//
// Coverted to Swift from Cameron Lowell Palmer’s Obj-C category
// (http://stackoverflow.com/a/23606211/253485)
//
90 91 92
// MARK: - Extension
extension String
{
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
    func stringByStrippingCharactersInSet(set:NSCharacterSet) -> String
    {
        return (self.componentsSeparatedByCharactersInSet(set) as NSArray).componentsJoinedByString("")
    }
    
    func stringByCollapsingWhitespace() -> String
    {
        var components:NSArray = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
        let predicate = NSPredicate(format: "self <> ''", argumentArray: nil)
        components = components.filteredArrayUsingPredicate(predicate)
        
        return components.componentsJoinedByString(" ")
    }
}

108 109 110 111
//
// A usable String interface for common actions, courtesy of 
// http://stackoverflow.com/a/25152652/253485
//
112 113 114
// MARK: - Extension
extension String
{
115
    // MARK: - substring
116 117
    func substringToIndex(index:Int) -> String
    {
118 119
        return self.substringToIndex(advance(self.startIndex, index))
    }
120 121 122 123


    func substringFromIndex(index:Int) -> String
    {
124 125
        return self.substringFromIndex(advance(self.startIndex, index))
    }
126 127 128 129
    
    
    func substringWithRange(range:Range<Int>) -> String
    {
130 131 132 133 134
        let start = advance(self.startIndex, range.startIndex)
        let end = advance(self.startIndex, range.endIndex)
        return self.substringWithRange(start..<end)
    }
    
135 136 137
    
    subscript(index:Int) -> Character
    {
138 139
        return self[advance(self.startIndex, index)]
    }
140 141 142 143
    
    
    subscript(range:Range<Int>) -> String
    {
144 145 146 147 148 149
        let start = advance(self.startIndex, range.startIndex)
        let end = advance(self.startIndex, range.endIndex)
        return self[start..<end]
    }
    
    // MARK: - replace
150 151
    func replaceCharactersInRange(range:Range<Int>, withString: String!) -> String
    {
152 153
        var result:NSMutableString = NSMutableString(string: self)
        result.replaceCharactersInRange(NSRange(range), withString: withString)
154
        return result as String
155
    }
156 157 158 159 160
}

// 
// Thanks to http://sketchytech.blogspot.co.uk/2014/08/pure-swift-stringbyreplacingoccurrences.html
//
161 162 163 164 165
// MARK: - Extension
extension String
{
    func rangesOfString(findStr:String) -> [Range<String.Index>]
    {
166 167 168 169
        var arr = [Range<String.Index>]()
        var startInd = self.startIndex
        var i = 0
        // test first of all whether the string is likely to appear at all
170 171
        if contains(self, first(findStr)!)
        {
172 173
            startInd = find(self,first(findStr)!)!
        }
174 175
        else
        {
176 177 178 179
            return arr
        }
        // set starting point for search based on the finding of the first character
        i = distance(self.startIndex, startInd)
180 181 182 183
        while i<=count(self)-count(findStr)
        {
            if self[advance(self.startIndex, i)..<advance(self.startIndex, i+count(findStr))] == findStr
            {
184 185
                arr.append(Range(start:advance(self.startIndex, i),end:advance(self.startIndex, i+count(findStr))))
                i = i+count(findStr)
186 187 188 189 190 191
            }
            i++
        }
        return arr
    } // try further optimization by repeating the initial act of finding first character after each found string
    
192 193 194
    
    func stringByReplacingOccurrencesOfString(string:String, replacement:String) -> String
    {
195 196 197 198
        // get ranges first using rangesOfString: method, then glue together the string using ranges of existing string and old string
        
        let ranges = self.rangesOfString(string)
        // if the string isn't found return unchanged string
199 200
        if ranges.isEmpty
        {
201 202 203 204 205
            return self
        }
        
        var newString = ""
        var startInd = self.startIndex
206 207
        for r in ranges
        {
208 209 210
            newString += self[startInd..<minElement(r)]
            newString += replacement
            
211 212
            if maxElement(r) < self.endIndex
            {
213 214 215 216 217
                startInd = advance(maxElement(r),1)
            }
        }
        
        // add the last part of the string after the final find
218 219
        if maxElement(ranges.last!) < self.endIndex
        {
220 221 222 223 224 225 226
            newString += self[advance(maxElement(ranges.last!),1)..<self.endIndex]
        }
        
        return newString
    }
}