Commit c693872f by Daniel Dahan

editor: reworked TextStorage and Text into Editor

parent b55650de
...@@ -7,6 +7,19 @@ ...@@ -7,6 +7,19 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
961276631DCD8B1800A7D920 /* CharacterAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961276621DCD8B1800A7D920 /* CharacterAttribute.swift */; };
961276641DCD8CF200A7D920 /* PresenterCard.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9631A7C01D95E3AC00CFB109 /* PresenterCard.swift */; settings = {ATTRIBUTES = (Public, ); }; };
961276651DCD8CF200A7D920 /* Capture.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96717B0D1DBE6AF600DA84DB /* Capture.swift */; settings = {ATTRIBUTES = (Public, ); }; };
961276661DCD8CF200A7D920 /* CapturePreview.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96717B0F1DBE6AF600DA84DB /* CapturePreview.swift */; settings = {ATTRIBUTES = (Public, ); }; };
961276671DCD8CF200A7D920 /* CaptureController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96717B0E1DBE6AF600DA84DB /* CaptureController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
961276681DCD8CF200A7D920 /* Editor.swift in Headers */ = {isa = PBXBuildFile; fileRef = 961DED451DCC40C500F425B6 /* Editor.swift */; settings = {ATTRIBUTES = (Public, ); }; };
961276691DCD8CF200A7D920 /* EditorController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 961DED4A1DCC546100F425B6 /* EditorController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9612766A1DCD8CF200A7D920 /* HeightPreset.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9626CB9A1DAD3D1D003E2611 /* HeightPreset.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9612766B1DCD8CF200A7D920 /* PhotoLibrary.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96717B161DBE6B1800DA84DB /* PhotoLibrary.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9612766C1DCD8CF200A7D920 /* PhotoLibraryController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96717B171DBE6B1800DA84DB /* PhotoLibraryController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9612766D1DCD8CF200A7D920 /* Pulse.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9631A7C61D95E5D900CFB109 /* Pulse.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9612766E1DCD8CF200A7D920 /* Display.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9626CA961DAB53A8003E2611 /* Display.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9612766F1DCD8CF200A7D920 /* CharacterAttribute.swift in Headers */ = {isa = PBXBuildFile; fileRef = 961276621DCD8B1800A7D920 /* CharacterAttribute.swift */; settings = {ATTRIBUTES = (Public, ); }; };
961DED461DCC40C500F425B6 /* Editor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961DED451DCC40C500F425B6 /* Editor.swift */; }; 961DED461DCC40C500F425B6 /* Editor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961DED451DCC40C500F425B6 /* Editor.swift */; };
961DED4B1DCC546100F425B6 /* EditorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961DED4A1DCC546100F425B6 /* EditorController.swift */; }; 961DED4B1DCC546100F425B6 /* EditorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961DED4A1DCC546100F425B6 /* EditorController.swift */; };
961EFC581D738FF600E84652 /* SnackbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961EFC571D738FF600E84652 /* SnackbarController.swift */; }; 961EFC581D738FF600E84652 /* SnackbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961EFC571D738FF600E84652 /* SnackbarController.swift */; };
...@@ -99,7 +112,6 @@ ...@@ -99,7 +112,6 @@
96BCB7E11CB40DC500C806FE /* Bar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7981CB40DC500C806FE /* Bar.swift */; }; 96BCB7E11CB40DC500C806FE /* Bar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7981CB40DC500C806FE /* Bar.swift */; };
96BCB7E21CB40DC500C806FE /* RootController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7991CB40DC500C806FE /* RootController.swift */; }; 96BCB7E21CB40DC500C806FE /* RootController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7991CB40DC500C806FE /* RootController.swift */; };
96BCB7E31CB40DC500C806FE /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79A1CB40DC500C806FE /* TabBar.swift */; }; 96BCB7E31CB40DC500C806FE /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79A1CB40DC500C806FE /* TabBar.swift */; };
96BCB7E41CB40DC500C806FE /* Text.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79B1CB40DC500C806FE /* Text.swift */; };
96BCB7E51CB40DC500C806FE /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79C1CB40DC500C806FE /* TextField.swift */; }; 96BCB7E51CB40DC500C806FE /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79C1CB40DC500C806FE /* TextField.swift */; };
96BCB7E61CB40DC500C806FE /* TextStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79D1CB40DC500C806FE /* TextStorage.swift */; }; 96BCB7E61CB40DC500C806FE /* TextStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79D1CB40DC500C806FE /* TextStorage.swift */; };
96BCB7E71CB40DC500C806FE /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79E1CB40DC500C806FE /* TextView.swift */; }; 96BCB7E71CB40DC500C806FE /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB79E1CB40DC500C806FE /* TextView.swift */; };
...@@ -159,7 +171,6 @@ ...@@ -159,7 +171,6 @@
96BCB8461CB4115200C806FE /* NavigationBar.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB7901CB40DC500C806FE /* NavigationBar.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 96BCB8461CB4115200C806FE /* NavigationBar.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB7901CB40DC500C806FE /* NavigationBar.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96BCB8471CB4115200C806FE /* NavigationController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB7911CB40DC500C806FE /* NavigationController.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 96BCB8471CB4115200C806FE /* NavigationController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB7911CB40DC500C806FE /* NavigationController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96BCB8481CB4115200C806FE /* NavigationItem.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB7921CB40DC500C806FE /* NavigationItem.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 96BCB8481CB4115200C806FE /* NavigationItem.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB7921CB40DC500C806FE /* NavigationItem.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96BCB8491CB4115200C806FE /* Text.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB79B1CB40DC500C806FE /* Text.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96BCB84A1CB4115200C806FE /* TextField.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB79C1CB40DC500C806FE /* TextField.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 96BCB84A1CB4115200C806FE /* TextField.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB79C1CB40DC500C806FE /* TextField.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96BCB84B1CB4115200C806FE /* TextStorage.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB79D1CB40DC500C806FE /* TextStorage.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 96BCB84B1CB4115200C806FE /* TextStorage.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB79D1CB40DC500C806FE /* TextStorage.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96BCB84C1CB4115200C806FE /* TextView.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB79E1CB40DC500C806FE /* TextView.swift */; settings = {ATTRIBUTES = (Public, ); }; }; 96BCB84C1CB4115200C806FE /* TextView.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96BCB79E1CB40DC500C806FE /* TextView.swift */; settings = {ATTRIBUTES = (Public, ); }; };
...@@ -205,6 +216,7 @@ ...@@ -205,6 +216,7 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
961276621DCD8B1800A7D920 /* CharacterAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterAttribute.swift; sourceTree = "<group>"; };
961DED451DCC40C500F425B6 /* Editor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Editor.swift; sourceTree = "<group>"; }; 961DED451DCC40C500F425B6 /* Editor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Editor.swift; sourceTree = "<group>"; };
961DED4A1DCC546100F425B6 /* EditorController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditorController.swift; sourceTree = "<group>"; }; 961DED4A1DCC546100F425B6 /* EditorController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditorController.swift; sourceTree = "<group>"; };
961EFC571D738FF600E84652 /* SnackbarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnackbarController.swift; sourceTree = "<group>"; }; 961EFC571D738FF600E84652 /* SnackbarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnackbarController.swift; sourceTree = "<group>"; };
...@@ -288,7 +300,6 @@ ...@@ -288,7 +300,6 @@
96BCB7981CB40DC500C806FE /* Bar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bar.swift; sourceTree = "<group>"; }; 96BCB7981CB40DC500C806FE /* Bar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bar.swift; sourceTree = "<group>"; };
96BCB7991CB40DC500C806FE /* RootController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootController.swift; sourceTree = "<group>"; }; 96BCB7991CB40DC500C806FE /* RootController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootController.swift; sourceTree = "<group>"; };
96BCB79A1CB40DC500C806FE /* TabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = "<group>"; }; 96BCB79A1CB40DC500C806FE /* TabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = "<group>"; };
96BCB79B1CB40DC500C806FE /* Text.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Text.swift; sourceTree = "<group>"; };
96BCB79C1CB40DC500C806FE /* TextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; }; 96BCB79C1CB40DC500C806FE /* TextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
96BCB79D1CB40DC500C806FE /* TextStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextStorage.swift; sourceTree = "<group>"; }; 96BCB79D1CB40DC500C806FE /* TextStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextStorage.swift; sourceTree = "<group>"; };
96BCB79E1CB40DC500C806FE /* TextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = "<group>"; }; 96BCB79E1CB40DC500C806FE /* TextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = "<group>"; };
...@@ -772,7 +783,7 @@ ...@@ -772,7 +783,7 @@
96BCB80E1CB4110E00C806FE /* TextView */ = { 96BCB80E1CB4110E00C806FE /* TextView */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
96BCB79B1CB40DC500C806FE /* Text.swift */, 961276621DCD8B1800A7D920 /* CharacterAttribute.swift */,
96BCB79D1CB40DC500C806FE /* TextStorage.swift */, 96BCB79D1CB40DC500C806FE /* TextStorage.swift */,
96BCB79E1CB40DC500C806FE /* TextView.swift */, 96BCB79E1CB40DC500C806FE /* TextView.swift */,
); );
...@@ -845,7 +856,6 @@ ...@@ -845,7 +856,6 @@
96BCB8461CB4115200C806FE /* NavigationBar.swift in Headers */, 96BCB8461CB4115200C806FE /* NavigationBar.swift in Headers */,
96BCB8471CB4115200C806FE /* NavigationController.swift in Headers */, 96BCB8471CB4115200C806FE /* NavigationController.swift in Headers */,
96BCB8481CB4115200C806FE /* NavigationItem.swift in Headers */, 96BCB8481CB4115200C806FE /* NavigationItem.swift in Headers */,
96BCB8491CB4115200C806FE /* Text.swift in Headers */,
96BCB84A1CB4115200C806FE /* TextField.swift in Headers */, 96BCB84A1CB4115200C806FE /* TextField.swift in Headers */,
96BCB84B1CB4115200C806FE /* TextStorage.swift in Headers */, 96BCB84B1CB4115200C806FE /* TextStorage.swift in Headers */,
96BCB84C1CB4115200C806FE /* TextView.swift in Headers */, 96BCB84C1CB4115200C806FE /* TextView.swift in Headers */,
...@@ -875,6 +885,18 @@ ...@@ -875,6 +885,18 @@
9697F7C61D8F2573004741EC /* PageTabBarController.swift in Headers */, 9697F7C61D8F2573004741EC /* PageTabBarController.swift in Headers */,
9697F7CB1D8F2573004741EC /* Snackbar.swift in Headers */, 9697F7CB1D8F2573004741EC /* Snackbar.swift in Headers */,
9697F7CC1D8F2573004741EC /* SnackbarController.swift in Headers */, 9697F7CC1D8F2573004741EC /* SnackbarController.swift in Headers */,
961276641DCD8CF200A7D920 /* PresenterCard.swift in Headers */,
961276651DCD8CF200A7D920 /* Capture.swift in Headers */,
961276661DCD8CF200A7D920 /* CapturePreview.swift in Headers */,
961276671DCD8CF200A7D920 /* CaptureController.swift in Headers */,
961276681DCD8CF200A7D920 /* Editor.swift in Headers */,
961276691DCD8CF200A7D920 /* EditorController.swift in Headers */,
9612766A1DCD8CF200A7D920 /* HeightPreset.swift in Headers */,
9612766B1DCD8CF200A7D920 /* PhotoLibrary.swift in Headers */,
9612766C1DCD8CF200A7D920 /* PhotoLibraryController.swift in Headers */,
9612766D1DCD8CF200A7D920 /* Pulse.swift in Headers */,
9612766E1DCD8CF200A7D920 /* Display.swift in Headers */,
9612766F1DCD8CF200A7D920 /* CharacterAttribute.swift in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
...@@ -1143,9 +1165,9 @@ ...@@ -1143,9 +1165,9 @@
96BCB7CD1CB40DC500C806FE /* PulseView.swift in Sources */, 96BCB7CD1CB40DC500C806FE /* PulseView.swift in Sources */,
96BCB7DA1CB40DC500C806FE /* NavigationController.swift in Sources */, 96BCB7DA1CB40DC500C806FE /* NavigationController.swift in Sources */,
96BCB7A81CB40DC500C806FE /* FabButton.swift in Sources */, 96BCB7A81CB40DC500C806FE /* FabButton.swift in Sources */,
96BCB7E41CB40DC500C806FE /* Text.swift in Sources */,
96717B121DBE6AF600DA84DB /* CaptureController.swift in Sources */, 96717B121DBE6AF600DA84DB /* CaptureController.swift in Sources */,
96717B181DBE6B1800DA84DB /* PhotoLibrary.swift in Sources */, 96717B181DBE6B1800DA84DB /* PhotoLibrary.swift in Sources */,
961276631DCD8B1800A7D920 /* CharacterAttribute.swift in Sources */,
96BCB7AB1CB40DC500C806FE /* ImageCard.swift in Sources */, 96BCB7AB1CB40DC500C806FE /* ImageCard.swift in Sources */,
96BCB7CB1CB40DC500C806FE /* PulseAnimation.swift in Sources */, 96BCB7CB1CB40DC500C806FE /* PulseAnimation.swift in Sources */,
96BCB7AE1CB40DC500C806FE /* Material+UIFont.swift in Sources */, 96BCB7AE1CB40DC500C806FE /* Material+UIFont.swift in Sources */,
......
/*
* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import UIKit
public enum CharacterAttribute: String {
case font = "NSFontAttributeName"
case paragraphStyle = "NSParagraphStyleAttributeName"
case forgroundColor = "NSForegroundColorAttributeName"
case backgroundColor = "NSBackgroundColorAttributeName"
case ligature = "NSLigatureAttributeName"
case kern = "NSKernAttributeName"
case strikethroughStyle = "NSStrikethroughStyleAttributeName"
case underlineStyle = "NSUnderlineStyleAttributeName"
case strokeColor = "NSStrokeColorAttributeName"
case strokeWidth = "NSStrokeWidthAttributeName"
case shadow = "NSShadowAttributeName"
case textEffect = "NSTextEffectAttributeName"
case attachment = "NSAttachmentAttributeName"
case link = "NSLinkAttributeName"
case baselineOffset = "NSBaselineOffsetAttributeName"
case underlineColor = "NSUnderlineColorAttributeName"
case strikethroughColor = "NSStrikethroughColorAttributeName"
case obliqueness = "NSObliquenessAttributeName"
case expansion = "NSExpansionAttributeName"
case writingDirection = "NSWritingDirectionAttributeName"
case verticalGlyphForm = "NSVerticalGlyphFormAttributeName"
}
public func CharacterAttributeToValue(attribute: CharacterAttribute) -> String {
switch attribute {
case .font:
return NSFontAttributeName
case .paragraphStyle:
return NSParagraphStyleAttributeName
case .forgroundColor:
return NSForegroundColorAttributeName
case .backgroundColor:
return NSBackgroundColorAttributeName
case .ligature:
return NSLigatureAttributeName
case .kern:
return NSKernAttributeName
case .strikethroughStyle:
return NSStrikethroughStyleAttributeName
case .underlineStyle:
return NSUnderlineStyleAttributeName
case .strokeColor:
return NSStrokeColorAttributeName
case .strokeWidth:
return NSStrokeWidthAttributeName
case .shadow:
return NSShadowAttributeName
case .textEffect:
return NSTextEffectAttributeName
case .attachment:
return NSAttachmentAttributeName
case .link:
return NSLinkAttributeName
case .baselineOffset:
return NSBaselineOffsetAttributeName
case .underlineColor:
return NSUnderlineColorAttributeName
case .strikethroughColor:
return NSStrikethroughColorAttributeName
case .obliqueness:
return NSObliquenessAttributeName
case .expansion:
return NSExpansionAttributeName
case .writingDirection:
return NSWritingDirectionAttributeName
case .verticalGlyphForm:
return NSVerticalGlyphFormAttributeName
}
}
extension NSAttributedString {
/**
Retrieves the character attributes that are currently applied.
- Parameter at location: An Int.
- Parameter effectiveRange: An optional NSRangePointer.
- Returns: A Dictionary of CharacterAttribute type keys and Any type values.
*/
open func characterAttributes(at location: Int, effectiveRange: NSRangePointer?) -> [CharacterAttribute: Any] {
var ca = [CharacterAttribute: Any]()
attributes(at: location, effectiveRange: effectiveRange).forEach { (key, value) in
guard let attribute = CharacterAttribute.init(rawValue: key) else {
return
}
ca[attribute] = value
}
return ca
}
}
extension NSMutableAttributedString {
/**
Adds a character attribute to a given range.
- Parameter characterAttribute: A CharacterAttribute.
- Parameter value: Any type.
- Parameter range: A NSRange.
*/
open func addAttribute(characterAttribute: CharacterAttribute, value: Any, range: NSRange) {
addAttribute(characterAttribute.rawValue, value: value, range: range)
}
/**
Removes a character attribute from a given range.
- Parameter characterAttribute: A CharacterAttribute.
- Parameter range: A NSRange.
*/
open func removeAttribute(characterAttribute: CharacterAttribute, range: NSRange) {
removeAttribute(characterAttribute.rawValue, range: range)
}
}
/*
* Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import UIKit
@objc(TextDelegate)
public protocol TextDelegate {
/**
An optional delegation method that is executed when
text will be processed during editing.
- Parameter text: The Text instance assodicated with the
delegation object.
- Parameter textStorage: The TextStorage instance
associated with the delegation object.
- Parameter string: The string value that is currently
being edited.
- Parameter range: The range of characters that are being
edited.
*/
@objc
optional func textWillProcessEdit(text: Text, textStorage: TextStorage, string: String, range: NSRange)
/**
An optional delegation method that is executed after
the edit processing has completed.
- Parameter text: The Text instance assodicated with the
delegation object.
- Parameter textStorage: The TextStorage instance
associated with the delegation object.
- Parameter string: The string value that was edited.
- Parameter result: A NSTextCheckingResult associated
with the processing result.
- Parameter flags: Matching flags.
- Parameter stop: Halts a service which is either
publishing or resolving.
*/
@objc
optional func textDidProcessEdit(text: Text, textStorage: TextStorage, string: String, result: NSTextCheckingResult?, flags: NSRegularExpression.MatchingFlags, stop: UnsafeMutablePointer<ObjCBool>)
}
@objc(Text)
public class Text: NSObject {
/// The string pattern to match within the textStorage.
public var pattern: String = "(^|\\s)#[\\d\\w_\u{203C}\u{2049}\u{20E3}\u{2122}\u{2139}\u{2194}-\u{2199}\u{21A9}-\u{21AA}\u{231A}-\u{231B}\u{23E9}-\u{23EC}\u{23F0}\u{23F3}\u{24C2}\u{25AA}-\u{25AB}\u{25B6}\u{25C0}\u{25FB}-\u{25FE}\u{2600}-\u{2601}\u{260E}\u{2611}\u{2614}-\u{2615}\u{261D}\u{263A}\u{2648}-\u{2653}\u{2660}\u{2663}\u{2665}-\u{2666}\u{2668}\u{267B}\u{267F}\u{2693}\u{26A0}-\u{26A1}\u{26AA}-\u{26AB}\u{26BD}-\u{26BE}\u{26C4}-\u{26C5}\u{26CE}\u{26D4}\u{26EA}\u{26F2}-\u{26F3}\u{26F5}\u{26FA}\u{26FD}\u{2702}\u{2705}\u{2708}-\u{270C}\u{270F}\u{2712}\u{2714}\u{2716}\u{2728}\u{2733}-\u{2734}\u{2744}\u{2747}\u{274C}\u{274E}\u{2753}-\u{2755}\u{2757}\u{2764}\u{2795}-\u{2797}\u{27A1}\u{27B0}\u{2934}-\u{2935}\u{2B05}-\u{2B07}\u{2B1B}-\u{2B1C}\u{2B50}\u{2B55}\u{3030}\u{303D}\u{3297}\u{3299}\u{1F004}\u{1F0CF}\u{1F170}-\u{1F171}\u{1F17E}-\u{1F17F}\u{1F18E}\u{1F191}-\u{1F19A}\u{1F1E7}-\u{1F1EC}\u{1F1EE}-\u{1F1F0}\u{1F1F3}\u{1F1F5}\u{1F1F7}-\u{1F1FA}\u{1F201}-\u{1F202}\u{1F21A}\u{1F22F}\u{1F232}-\u{1F23A}\u{1F250}-\u{1F251}\u{1F300}-\u{1F320}\u{1F330}-\u{1F335}\u{1F337}-\u{1F37C}\u{1F380}-\u{1F393}\u{1F3A0}-\u{1F3C4}\u{1F3C6}-\u{1F3CA}\u{1F3E0}-\u{1F3F0}\u{1F400}-\u{1F43E}\u{1F440}\u{1F442}-\u{1F4F7}\u{1F4F9}-\u{1F4FC}\u{1F500}-\u{1F507}\u{1F509}-\u{1F53D}\u{1F550}-\u{1F567}\u{1F5FB}-\u{1F640}\u{1F645}-\u{1F64F}\u{1F680}-\u{1F68A}]+" {
didSet {
prepareTextStorageExpression()
}
}
/// TextStorage instance that is observed while editing.
public private(set) var textStorage: TextStorage = TextStorage()
/// Delegation object for pre and post text processing.
open weak var delegate: TextDelegate?
/// Initializer.
public override init() {
super.init()
prepareTextStorageExpression()
prepareTextStorageProcessingCallbacks()
}
/**
A convenience property that accesses the textStorage
string.
*/
public var string: String {
return textStorage.string
}
/// An Array of matches that match the pattern expression.
public var matches: Array<String> {
return textStorage.expression!.matches(in: string, options: [], range: NSMakeRange(0, string.utf16.count)).map { [unowned self] in
(self.string as NSString).substring(with: $0.range).trimmed
}
}
/**
An Array of unique matches that match the pattern
expression.
*/
public var uniqueMatches: Array<String> {
var seen: [String: Bool] = [:]
return matches.filter { nil == seen.updateValue(true, forKey: $0) }
}
/// Prepares the TextStorage regular expression for matching.
private func prepareTextStorageExpression() {
textStorage.expression = try? NSRegularExpression(pattern: pattern, options: [])
}
/// Prepares the pre and post processing callbacks.
private func prepareTextStorageProcessingCallbacks() {
textStorage.textWillProcessEdit = { [weak self] (textStorage: TextStorage, string: String, range: NSRange) -> Void in
if let s: Text = self {
s.delegate?.textWillProcessEdit?(text: s, textStorage: textStorage, string: string, range: range)
}
}
textStorage.textDidProcessEdit = { [weak self] (textStorage: TextStorage, result: NSTextCheckingResult?, flags: NSRegularExpression.MatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
if let s: Text = self {
s.delegate?.textDidProcessEdit?(text: s, textStorage: textStorage, string: textStorage.string, result: result, flags: flags, stop: stop)
}
}
}
}
...@@ -30,21 +30,37 @@ ...@@ -30,21 +30,37 @@
import UIKit import UIKit
internal typealias TextWillProcessEdit = (TextStorage, String, NSRange) -> Void @objc(TextStorageDelegate)
internal typealias TextDidProcessEdit = (TextStorage, NSTextCheckingResult?, NSRegularExpression.MatchingFlags, UnsafeMutablePointer<ObjCBool>) -> Void public protocol TextStorageDelegate: NSTextStorageDelegate {
/**
A delegation method that is executed when text will be
processed during editing.
- Parameter textStorage: A TextStorage.
- Parameter willProcessEditing text: A String.
- Parameter range: A NSRange.
*/
@objc
optional func textStorage(textStorage: TextStorage, willProcessEditing text: String, range: NSRange)
/**
A delegation method that is executed when text has been
processed after editing.
- Parameter textStorage: A TextStorage.
- Parameter didProcessEditing text: A String.
- Parameter result: An optional NSTextCheckingResult.
- Parameter flags: NSRegularExpression.MatchingFlags.
- Parameter top: An UnsafeMutablePointer<ObjCBool>.
*/
@objc
optional func textStorage(textStorage: TextStorage, didProcessEditing text: String, result: NSTextCheckingResult?, flags: NSRegularExpression.MatchingFlags, stop: UnsafeMutablePointer<ObjCBool>)
}
public class TextStorage: NSTextStorage { open class TextStorage: NSTextStorage {
/// A callback that is executed when a process edit will happen.
internal var textWillProcessEdit: TextWillProcessEdit?
/// A callback that is executed when a process edit did happen.
internal var textDidProcessEdit: TextDidProcessEdit?
/// A storage facility for attributed text. /// A storage facility for attributed text.
public lazy var store: NSMutableAttributedString = NSMutableAttributedString() open fileprivate(set) var store: NSMutableAttributedString!
/// The regular expression to match text fragments against. /// The regular expression to match text fragments against.
public var expression: NSRegularExpression? open var expression: NSRegularExpression?
/// Initializer. /// Initializer.
public required init?(coder aDecoder: NSCoder) { public required init?(coder aDecoder: NSCoder) {
...@@ -54,60 +70,78 @@ public class TextStorage: NSTextStorage { ...@@ -54,60 +70,78 @@ public class TextStorage: NSTextStorage {
/// Initializer. /// Initializer.
public override init() { public override init() {
super.init() super.init()
prepareStore()
} }
}
extension TextStorage {
/// Prepare the store.
fileprivate func prepareStore() {
store = NSMutableAttributedString()
}
}
extension TextStorage {
/// A String value of the attirbutedString property. /// A String value of the attirbutedString property.
public override var string: String { open override var string: String {
return store.string return store.string
} }
/// Processes the text when editing. /// Processes the text when editing.
public override func processEditing() { open override func processEditing() {
let range: NSRange = (string as NSString).paragraphRange(for: editedRange) let range: NSRange = (string as NSString).paragraphRange(for: editedRange)
textWillProcessEdit?(self, string, range) (delegate as? TextStorageDelegate)?.textStorage?(textStorage: self, willProcessEditing: string, range: range)
expression!.enumerateMatches(in: string, options: [], range: range) { (result: NSTextCheckingResult?, flags: NSRegularExpression.MatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) -> Void in expression!.enumerateMatches(in: string, options: [], range: range) { [weak self] (result: NSTextCheckingResult?, flags: NSRegularExpression.MatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
self.textDidProcessEdit?(self, result, flags, stop) guard let s = self else {
return
}
(s.delegate as? TextStorageDelegate)?.textStorage!(textStorage: s, didProcessEditing: s.string, result: result, flags: flags, stop: stop)
} }
super.processEditing() super.processEditing()
} }
/** /**
Returns the attributes for the character at a given index. Returns the attributes for the character at a given index.
- Parameter location: The index for which to return attributes. - Parameter location: The index for which to return attributes.
This value must lie within the bounds of the receiver. This value must lie within the bounds of the receiver.
- Parameter range: Upon return, the range over which the - Parameter range: Upon return, the range over which the
attributes and values are the same as those at index. This range attributes and values are the same as those at index. This range
isn’t necessarily the maximum range covered, and its extent is isn’t necessarily the maximum range covered, and its extent is
implementation-dependent. If you need the maximum range, use implementation-dependent. If you need the maximum range, use
attributesAtIndex:longestEffectiveRange:inRange:. attributesAtIndex:longestEffectiveRange:inRange:.
If you don't need this value, pass NULL. If you don't need this value, pass NULL.
- Returns: The attributes for the character at index. - Returns: The attributes for the character at index.
*/ */
public override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [String : Any] { open override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [String : Any] {
return store.attributes(at: location, effectiveRange: range) return store.attributes(at: location, effectiveRange: range)
} }
/** /**
Replaces a range of text with a string value. Replaces a range of text with a string value.
- Parameter range: The character range to replace. - Parameter range: The character range to replace.
- Parameter str: The string value that the characters - Parameter str: The string value that the characters
will be replaced with. will be replaced with.
*/ */
public override func replaceCharacters(in range: NSRange, with str: String) { open override func replaceCharacters(in range: NSRange, with str: String) {
store.replaceCharacters(in: range, with: str) store.replaceCharacters(in: range, with: str)
edited(NSTextStorageEditActions.editedCharacters, range: range, changeInLength: str.utf16.count - range.length)
edited(.editedCharacters, range: range, changeInLength: str.utf16.count - range.length)
} }
/** /**
Sets the attributedString attribute values. Sets the attributedString attribute values.
- Parameter attrs: The attributes to set. - Parameter attrs: The attributes to set.
- Parameter range: A range of characters that will have their - Parameter range: A range of characters that will have their
attributes updated. attributes updated.
*/ */
public override func setAttributes(_ attrs: [String : Any]?, range: NSRange) { open override func setAttributes(_ attrs: [String : Any]?, range: NSRange) {
store.setAttributes(attrs, range: range) store.setAttributes(attrs, range: range)
edited(NSTextStorageEditActions.editedAttributes, range: range, changeInLength: 0)
edited(.editedAttributes, range: range, changeInLength: 0)
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment