Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
Material
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dmitriy Stepanets
Material
Commits
dc116e17
Unverified
Commit
dc116e17
authored
Mar 10, 2017
by
Daniel Dahan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
development: removed Editor as now TextView is self contained
parent
09b0f7a4
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
3 additions
and
606 deletions
+3
-606
Material.xcodeproj/project.pbxproj
+0
-14
Sources/iOS/CharacterAttribute.swift
+3
-3
Sources/iOS/Editor.swift
+0
-589
No files found.
Material.xcodeproj/project.pbxproj
View file @
dc116e17
...
...
@@ -18,7 +18,6 @@
9617B0811DFCA8CF00410F8F
/* Capture.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96717B0D1DBE6AF600DA84DB
/* Capture.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
9617B0821DFCA8CF00410F8F
/* CapturePreview.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96717B0F1DBE6AF600DA84DB
/* CapturePreview.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
9617B0831DFCA8CF00410F8F
/* CaptureController.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96717B0E1DBE6AF600DA84DB
/* CaptureController.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
9617B0841DFCA8CF00410F8F
/* Editor.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
961DED451DCC40C500F425B6
/* Editor.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
9617B0861DFCA8CF00410F8F
/* HeightPreset.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9626CB9A1DAD3D1D003E2611
/* HeightPreset.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
9617B0871DFCA8CF00410F8F
/* PageTabBarController.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
963FBF071D669D14008F8512
/* PageTabBarController.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
9617B0881DFCA8CF00410F8F
/* PhotoLibrary.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96717B161DBE6B1800DA84DB
/* PhotoLibrary.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
...
...
@@ -116,7 +115,6 @@
965E81211DD4D5C800D61E4B
/* TextStorage.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BCB79D1CB40DC500C806FE
/* TextStorage.swift */
;
};
965E81221DD4D5C800D61E4B
/* TextView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BCB79E1CB40DC500C806FE
/* TextView.swift */
;
};
965E81231DD4D7C800D61E4B
/* BottomTabBar.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96BCB7591CB40DC500C806FE
/* BottomTabBar.swift */
;
};
965E81241DD4D7C800D61E4B
/* Editor.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
961DED451DCC40C500F425B6
/* Editor.swift */
;
};
965E81261DD4D7C800D61E4B
/* CharacterAttribute.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
961276621DCD8B1800A7D920
/* CharacterAttribute.swift */
;
};
9697F7BF1D8F2572004741EC
/* Divider.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96230AB71D6A520C00AF47DC
/* Divider.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
9697F7C01D8F2572004741EC
/* Material+CALayer.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
96F1DC871D654FDF0025F925
/* Material+CALayer.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
...
...
@@ -193,7 +191,6 @@
/* Begin PBXFileReference section */
961276621DCD8B1800A7D920
/* CharacterAttribute.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CharacterAttribute.swift
;
sourceTree
=
"<group>"
;
};
961730591E145DE900A9A297
/* CollectionViewCard.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
CollectionViewCard.swift
;
sourceTree
=
"<group>"
;
};
961DED451DCC40C500F425B6
/* Editor.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Editor.swift
;
sourceTree
=
"<group>"
;
};
961E6BDE1DDA2A95004E6C93
/* Application.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Application.swift
;
sourceTree
=
"<group>"
;
};
961E6BE11DDA2AF3004E6C93
/* Screen.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Screen.swift
;
sourceTree
=
"<group>"
;
};
961EFC571D738FF600E84652
/* SnackbarController.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
SnackbarController.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -308,14 +305,6 @@
name
=
TextField
;
sourceTree
=
"<group>"
;
};
961DED441DCC40AC00F425B6
/* Editor */
=
{
isa
=
PBXGroup
;
children
=
(
961DED451DCC40C500F425B6
/* Editor.swift */
,
);
name
=
Editor
;
sourceTree
=
"<group>"
;
};
961E6BDD1DDA2A7E004E6C93
/* Application */
=
{
isa
=
PBXGroup
;
children
=
(
...
...
@@ -526,7 +515,6 @@
96328B9A1E05C135009A4C90
/* Data */
,
96BCB80B1CB410CC00C806FE
/* Device */
,
96230AB61D6A51FD00AF47DC
/* Divider */
,
961DED441DCC40AC00F425B6
/* Editor */
,
96BCB80A1CB410A100C806FE
/* Extension */
,
96BCB8071CB4101C00C806FE
/* Font */
,
9602F00C1DA1163000F3FB79
/* Grid */
,
...
...
@@ -817,7 +805,6 @@
9617B0811DFCA8CF00410F8F
/* Capture.swift in Headers */
,
9617B0821DFCA8CF00410F8F
/* CapturePreview.swift in Headers */
,
9617B0831DFCA8CF00410F8F
/* CaptureController.swift in Headers */
,
9617B0841DFCA8CF00410F8F
/* Editor.swift in Headers */
,
9617B0861DFCA8CF00410F8F
/* HeightPreset.swift in Headers */
,
9617B0871DFCA8CF00410F8F
/* PageTabBarController.swift in Headers */
,
9617B0881DFCA8CF00410F8F
/* PhotoLibrary.swift in Headers */
,
...
...
@@ -923,7 +910,6 @@
buildActionMask
=
2147483647
;
files
=
(
965E81231DD4D7C800D61E4B
/* BottomTabBar.swift in Sources */
,
965E81241DD4D7C800D61E4B
/* Editor.swift in Sources */
,
961E6BE21DDA2AF3004E6C93
/* Screen.swift in Sources */
,
965E81261DD4D7C800D61E4B
/* CharacterAttribute.swift in Sources */
,
965E80FF1DD4D5C800D61E4B
/* BottomNavigationController.swift in Sources */
,
...
...
Sources/iOS/CharacterAttribute.swift
View file @
dc116e17
...
...
@@ -117,7 +117,7 @@ extension NSMutableAttributedString {
- Parameter characterAttributes: A Dictionary of CharacterAttribute type keys and Any type values.
- Parameter range: A NSRange.
*/
open
func
addAttributes
(
characterAttributes
:
[
CharacterAttribute
:
Any
]
=
[:
],
range
:
NSRange
)
{
open
func
addAttributes
(
characterAttributes
:
[
CharacterAttribute
:
Any
],
range
:
NSRange
)
{
for
(
k
,
v
)
in
characterAttributes
{
addAttribute
(
characterAttribute
:
k
,
value
:
v
,
range
:
range
)
}
...
...
@@ -139,7 +139,7 @@ extension NSMutableAttributedString {
- Parameter characterAttributes: A Dictionary of CharacterAttribute type keys and Any type values.
- Parameter range: A NSRange.
*/
open
func
updateAttributes
(
characterAttributes
:
[
CharacterAttribute
:
Any
]
=
[:
],
range
:
NSRange
)
{
open
func
updateAttributes
(
characterAttributes
:
[
CharacterAttribute
:
Any
],
range
:
NSRange
)
{
for
(
k
,
v
)
in
characterAttributes
{
updateAttribute
(
characterAttribute
:
k
,
value
:
v
,
range
:
range
)
}
...
...
@@ -159,7 +159,7 @@ extension NSMutableAttributedString {
- Parameter characterAttributes: An Array of CharacterAttributes.
- Parameter range: A NSRange.
*/
open
func
removeAttributes
(
characterAttributes
:
[
CharacterAttribute
]
=
[]
,
range
:
NSRange
)
{
open
func
removeAttributes
(
characterAttributes
:
[
CharacterAttribute
],
range
:
NSRange
)
{
for
k
in
characterAttributes
{
removeAttribute
(
characterAttribute
:
k
,
range
:
range
)
}
...
...
Sources/iOS/Editor.swift
deleted
100644 → 0
View file @
09b0f7a4
/*
* Copyright (C) 2015 - 2017, 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(EditorDelegate)
public
protocol
EditorDelegate
{
/**
A delegation method that is executed when text will be
processed during editing.
- Parameter editor: An Editor.
- Parameter willProcessEditing textStorage: A TextStorage.
- Parameter text: A String.
- Parameter range: A NSRange.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
willProcessEditing
textStorage
:
TextStorage
,
text
:
String
,
range
:
NSRange
)
/**
A delegation method that is executed when text has been
processed after editing.
- Parameter editor: An Editor.
- Parameter didProcessEditing textStorage: A TextStorage.
- Parameter text: A String.
- Parameter range: A NSRange.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
didProcessEditing
textStorage
:
TextStorage
,
text
:
String
,
range
:
NSRange
)
/**
A delegation method that is executed when the textView should begin editing.
- Parameter editor: An Editor.
- Parameter shouldBeginEditing textView: A UITextView.
- Returns: A boolean indicating if the textView should begin editing, true if
yes, false otherwise.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
shouldBeginEditing
textView
:
UITextView
)
->
Bool
/**
A delegation method that is executed when the textView should end editing.
- Parameter editor: An Editor.
- Parameter shouldEndEditing textView: A UITextView.
- Returns: A boolean indicating if the textView should end editing, true if
yes, false otherwise.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
shouldEndEditing
textView
:
UITextView
)
->
Bool
/**
A delegation method that is executed when the textView did begin editing.
- Parameter editor: An Editor.
- Parameter didBeginEditing textView: A UITextView.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
didBeginEditing
textView
:
UITextView
)
/**
A delegation method that is executed when the textView did begin editing.
- Parameter editor: An Editor.
- Parameter didBeginEditing textView: A UITextView.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
didEndEditing
textView
:
UITextView
)
/**
A delegation method that is executed when the textView should change text in
a given range with replacement text.
- Parameter editor: An Editor.
- Parameter textView: A UITextView.
- Parameter shouldChangeTextIn range: A NSRange.
- Parameter replacementText text: A String.
- Returns: A boolean indicating if the textView should change text in a given
range with the given replacement text, true if yes, false otherwise.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
textView
:
UITextView
,
shouldChangeTextIn
range
:
NSRange
,
replacementText
text
:
String
)
->
Bool
/**
A delegation method that is executed when the textView did change.
- Parameter editor: An Editor.
- Parameter didChange textView: A UITextView.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
didChange
textView
:
UITextView
)
/**
A delegation method that is executed when the textView did change a selection.
- Parameter editor: An Editor.
- Parameter didChangeSelection textView: A UITextView.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
didChangeSelection
textView
:
UITextView
)
/**
A delegation method that is executed when the textView should interact with
a URL in a given character range.
- Parameter editor: An Editor.
- Parameter textView: A UITextView.
- Parameter shouldInteractWith URL: A URL.
- Parameter in characterRange: A Range.
- Returns: A boolean indicating if the textView should interact with a URL in
a given character range, true if yes, false otherwise.
@available(iOS, introduced: 8.0, deprecated: 10.0)
@objc
optional func editor(editor: Editor, textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool
A delegation method that is executed when the textView should interact with
a text attachment in a given character range.
- Parameter editor: An Editor.
- Parameter textView: A UITextView.
- Parameter shouldInteractWith textAttachment: A NSTextAttachment.
- Parameter in characterRange: A Range.
- Returns: A boolean indicating if the textView should interact with a
NSTextAttachment in a given character range, true if yes, false otherwise.
@available(iOS, introduced: 8.0, deprecated: 10.0)
@objc
optional func editor(editor: Editor, textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange) -> Bool
A delegation method that is executed when the textView should interact with
a URL in a given character range.
- Parameter editor: An Editor.
- Parameter textView: A UITextView.
- Parameter shouldInteractWith URL: A URL.
- Parameter in characterRange: A Range.
- Parameter interaction: A UITextItemInteraction.
- Returns: A boolean indicating if the textView should interact with a URL in
a given character range, true if yes, false otherwise.
@available(iOS 10.0, *)
@objc
optional func editor(editor: Editor, textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool
A delegation method that is executed when the textView should interact with
a text attachment in a given character range.
- Parameter editor: An Editor.
- Parameter textView: A UITextView.
- Parameter shouldInteractWith textAttachment: A NSTextAttachment.
- Parameter in characterRange: A Range.
- Parameter interaction: A UITextItemInteraction.
- Returns: A boolean indicating if the textView should interact with a
NSTextAttachment in a given character range, true if yes, false otherwise.
@available(iOS 10.0, *)
@objc
optional func editor(editor: Editor, textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool
*/
/**
A delegation method that is executed when the keyboard will open.
- Parameter editor: An Editor.
- Parameter willShowKeyboard value: A NSValue.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
willShowKeyboard
value
:
NSValue
)
/**
A delegation method that is executed when the keyboard will close.
- Parameter editor: An Editor.
- Parameter willHideKeyboard value: A NSValue.
*/
@objc
optional
func
editor
(
editor
:
Editor
,
willHideKeyboard
value
:
NSValue
)
}
open
class
Editor
:
View
{
/// Will layout the view.
open
var
willLayout
:
Bool
{
return
0
<
width
&&
0
<
height
&&
nil
!=
superview
}
/// Is the keyboard hidden.
open
fileprivate
(
set
)
var
isKeyboardHidden
=
true
/// TextStorage instance that is observed while editing.
open
fileprivate
(
set
)
var
textStorage
:
TextStorage
!
/// A reference to the NSTextContainer.
open
fileprivate
(
set
)
var
textContainer
:
NSTextContainer
!
/// A reference to the NSLayoutManager.
open
fileprivate
(
set
)
var
layoutManager
:
NSLayoutManager
!
/// A reference to the textView inputAccessoryView.
@IBInspectable
open
override
var
inputAccessoryView
:
UIView
?
{
get
{
return
textView
.
inputAccessoryView
}
set
(
value
)
{
textView
.
inputAccessoryView
=
value
}
}
/// A preset wrapper around textViewEdgeInsets.
open
var
textViewEdgeInsetsPreset
=
EdgeInsetsPreset
.
none
{
didSet
{
textViewEdgeInsets
=
EdgeInsetsPresetToValue
(
preset
:
textViewEdgeInsetsPreset
)
}
}
/// A reference to textViewEdgeInsets.
@IBInspectable
open
var
textViewEdgeInsets
=
EdgeInsets
.
zero
{
didSet
{
layoutSubviews
()
}
}
/// Reference to the TextView.
open
fileprivate
(
set
)
var
textView
:
TextView
!
/// The placeholderLabel font value.
@IBInspectable
open
var
font
:
UIFont
?
{
get
{
return
placeholderLabel
.
font
}
set
(
value
)
{
placeholderLabel
.
font
=
value
textView
.
font
=
value
}
}
/// The placeholderLabel text value.
@IBInspectable
open
var
placeholder
:
String
?
{
get
{
return
placeholderLabel
.
text
}
set
(
value
)
{
placeholderLabel
.
text
=
value
layoutSubviews
()
}
}
/// The placeholder UILabel.
@IBInspectable
open
let
placeholderLabel
=
UILabel
()
/// Placeholder normal text
@IBInspectable
open
var
placeholderNormalColor
=
Color
.
darkText
.
others
{
didSet
{
updatePlaceholderLabelColor
()
}
}
/// Placeholder active text
@IBInspectable
open
var
placeholderActiveColor
=
Color
.
blue
.
base
{
didSet
{
updatePlaceholderLabelColor
()
}
}
/// Placeholder UILabel EdgeInsets preset property.
open
var
placeholderLabelEdgeInsetsPreset
=
EdgeInsetsPreset
.
none
{
didSet
{
placeholderLabelEdgeInsets
=
EdgeInsetsPresetToValue
(
preset
:
placeholderLabelEdgeInsetsPreset
)
}
}
/// Placeholder UILabel EdgeInsets property.
open
var
placeholderLabelEdgeInsets
=
EdgeInsets
.
zero
{
didSet
{
layoutSubviews
()
}
}
/// An override to the text property.
@IBInspectable
open
var
text
:
String
?
{
get
{
return
textView
.
text
}
set
(
value
)
{
textView
.
text
=
value
}
}
/// An override to the attributedText property.
open
var
attributedText
:
NSAttributedString
!
{
get
{
return
textView
.
attributedText
}
set
(
value
)
{
textView
.
attributedText
=
value
}
}
/// A reference to an EditorDelegate.
open
weak
var
delegate
:
EditorDelegate
?
/// The string pattern to match within the textStorage.
open
var
pattern
=
"(^|
\\
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
{
prepareRegularExpression
()
}
}
/**
A convenience property that accesses the textStorage
string.
*/
open
var
string
:
String
{
return
textStorage
.
string
}
/// An Array of matches that match the pattern expression.
open
var
matches
:
[
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.
*/
open
var
uniqueMatches
:
[
String
]
{
var
seen
=
[
String
:
Bool
]()
return
matches
.
filter
{
nil
==
seen
.
updateValue
(
true
,
forKey
:
$0
)
}
}
open
override
func
layoutSubviews
()
{
super
.
layoutSubviews
()
guard
willLayout
else
{
return
}
textView
.
frame
=
CGRect
(
x
:
textViewEdgeInsets
.
left
,
y
:
textViewEdgeInsets
.
top
,
width
:
width
-
textViewEdgeInsets
.
left
-
textViewEdgeInsets
.
right
,
height
:
height
-
textViewEdgeInsets
.
top
-
textViewEdgeInsets
.
bottom
)
placeholderLabel
.
preferredMaxLayoutWidth
=
textContainer
.
size
.
width
-
textContainer
.
lineFragmentPadding
*
2
layout
(
placeholderLabel
)
.
edges
(
top
:
placeholderLabelEdgeInsets
.
top
,
left
:
placeholderLabelEdgeInsets
.
left
+
textContainer
.
lineFragmentPadding
,
bottom
:
placeholderLabelEdgeInsets
.
bottom
,
right
:
placeholderLabelEdgeInsets
.
right
+
textContainer
.
lineFragmentPadding
)
}
/// Deinitializer.
deinit
{
NotificationCenter
.
default
.
removeObserver
(
self
)
}
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open
override
func
prepare
()
{
super
.
prepare
()
prepareTextContainer
()
prepareLayoutManager
()
prepareTextStorage
()
prepareRegularExpression
()
prepareTextView
()
preparePlaceholderLabel
()
prepareKeyboardNotificationObservers
()
}
}
extension
Editor
{
/// Prepares the textContainer.
fileprivate
func
prepareTextContainer
()
{
textContainer
=
NSTextContainer
(
size
:
bounds
.
size
)
}
/// Prepares the layoutManager.
fileprivate
func
prepareLayoutManager
()
{
layoutManager
=
NSLayoutManager
()
layoutManager
.
addTextContainer
(
textContainer
)
}
/// Prepares the textStorage.
fileprivate
func
prepareTextStorage
()
{
textStorage
=
TextStorage
()
textStorage
.
addLayoutManager
(
layoutManager
)
textStorage
.
delegate
=
self
}
/// Prepares the textView.
fileprivate
func
prepareTextView
()
{
textView
=
TextView
(
textContainer
:
textContainer
)
textView
.
delegate
=
self
addSubview
(
textView
)
}
/// Prepares the regular expression for matching.
fileprivate
func
prepareRegularExpression
()
{
textStorage
.
expression
=
try
?
NSRegularExpression
(
pattern
:
pattern
,
options
:
[])
}
/// prepares the placeholderLabel property.
fileprivate
func
preparePlaceholderLabel
()
{
placeholderLabel
.
font
=
font
placeholderLabel
.
textAlignment
=
textView
.
textAlignment
placeholderLabel
.
numberOfLines
=
0
placeholderLabel
.
backgroundColor
=
.
clear
}
/// Prepares the keyboard notification center observers.
fileprivate
func
prepareKeyboardNotificationObservers
()
{
let
defaultCenter
=
NotificationCenter
.
default
defaultCenter
.
addObserver
(
self
,
selector
:
#selector(
handleKeyboardWillShow(notification:)
)
,
name
:
NSNotification
.
Name
.
UIKeyboardWillShow
,
object
:
nil
)
defaultCenter
.
addObserver
(
self
,
selector
:
#selector(
handleKeyboardWillHide(notification:)
)
,
name
:
NSNotification
.
Name
.
UIKeyboardWillHide
,
object
:
nil
)
defaultCenter
.
addObserver
(
textView
,
selector
:
#selector(
handleTextViewTextDidBegin
)
,
name
:
NSNotification
.
Name
.
UITextViewTextDidBeginEditing
,
object
:
self
)
defaultCenter
.
addObserver
(
textView
,
selector
:
#selector(
handleTextViewTextDidChange
)
,
name
:
NSNotification
.
Name
.
UITextViewTextDidChange
,
object
:
self
)
defaultCenter
.
addObserver
(
textView
,
selector
:
#selector(
handleTextViewTextDidEnd
)
,
name
:
NSNotification
.
Name
.
UITextViewTextDidEndEditing
,
object
:
self
)
}
}
extension
Editor
{
/// Updates the placeholderLabel text color.
fileprivate
func
updatePlaceholderLabelColor
()
{
tintColor
=
placeholderActiveColor
placeholderLabel
.
textColor
=
textView
.
isEditing
?
placeholderActiveColor
:
placeholderNormalColor
}
}
extension
Editor
{
/**
Handler for when the keyboard will open.
- Parameter notification: A Notification.
*/
@objc
fileprivate
func
handleKeyboardWillShow
(
notification
:
Notification
)
{
guard
isKeyboardHidden
else
{
return
}
isKeyboardHidden
=
false
guard
let
v
=
notification
.
userInfo
?[
UIKeyboardFrameBeginUserInfoKey
]
as?
NSValue
else
{
return
}
delegate
?
.
editor
?(
editor
:
self
,
willShowKeyboard
:
v
)
}
/**
Handler for when the keyboard will close.
- Parameter notification: A Notification.
*/
@objc
fileprivate
func
handleKeyboardWillHide
(
notification
:
Notification
)
{
guard
!
isKeyboardHidden
else
{
return
}
isKeyboardHidden
=
true
guard
let
v
=
notification
.
userInfo
?[
UIKeyboardFrameEndUserInfoKey
]
as?
NSValue
else
{
return
}
delegate
?
.
editor
?(
editor
:
self
,
willHideKeyboard
:
v
)
}
/// Notification handler for when text editing began.
@objc
fileprivate
func
handleTextViewTextDidBegin
()
{
}
/// Notification handler for when text changed.
@objc
fileprivate
func
handleTextViewTextDidChange
()
{
}
/// Notification handler for when text editing ended.
@objc
fileprivate
func
handleTextViewTextDidEnd
()
{
}
}
extension
Editor
:
TextStorageDelegate
{
@objc
open
func
textStorage
(
textStorage
:
TextStorage
,
willProcessEditing
text
:
String
,
range
:
NSRange
)
{
delegate
?
.
editor
?(
editor
:
self
,
willProcessEditing
:
textStorage
,
text
:
string
,
range
:
range
)
}
@objc
open
func
textStorage
(
textStorage
:
TextStorage
,
didProcessEditing
text
:
String
,
result
:
NSTextCheckingResult
?,
flags
:
NSRegularExpression
.
MatchingFlags
,
stop
:
UnsafeMutablePointer
<
ObjCBool
>
)
{
guard
let
range
=
result
?
.
range
else
{
return
}
delegate
?
.
editor
?(
editor
:
self
,
didProcessEditing
:
textStorage
,
text
:
string
,
range
:
range
)
}
}
extension
Editor
:
UITextViewDelegate
{
@objc
open
func
textViewShouldBeginEditing
(
_
textView
:
UITextView
)
->
Bool
{
return
delegate
?
.
editor
?(
editor
:
self
,
shouldBeginEditing
:
textView
)
??
true
}
@objc
open
func
textViewShouldEndEditing
(
_
textView
:
UITextView
)
->
Bool
{
return
delegate
?
.
editor
?(
editor
:
self
,
shouldEndEditing
:
textView
)
??
true
}
@objc
open
func
textViewDidBeginEditing
(
_
textView
:
UITextView
)
{
delegate
?
.
editor
?(
editor
:
self
,
didBeginEditing
:
textView
)
}
@objc
open
func
textViewDidEndEditing
(
_
textView
:
UITextView
)
{
delegate
?
.
editor
?(
editor
:
self
,
didEndEditing
:
textView
)
}
@objc
open
func
textView
(
_
textView
:
UITextView
,
shouldChangeTextIn
range
:
NSRange
,
replacementText
text
:
String
)
->
Bool
{
return
delegate
?
.
editor
?(
editor
:
self
,
textView
:
textView
,
shouldChangeTextIn
:
range
,
replacementText
:
text
)
??
true
}
@objc
open
func
textViewDidChange
(
_
textView
:
UITextView
)
{
delegate
?
.
editor
?(
editor
:
self
,
didChange
:
textView
)
}
@objc
open
func
textViewDidChangeSelection
(
_
textView
:
UITextView
)
{
delegate
?
.
editor
?(
editor
:
self
,
didChangeSelection
:
textView
)
}
}
/*
@available(iOS, introduced: 8.0, deprecated: : 10.0)
extension Editor {
@objc
open func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
return delegate?.editor?(editor: self, textView: textView, shouldInteractWith: URL, in: characterRange) ?? true
}
@objc
open func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange) -> Bool {
return delegate?.editor?(editor: self, textView: textView, shouldInteractWith: textAttachment, in: characterRange) ?? true
}
}
@available(iOS 10.0, *)
extension Editor {
@objc
open func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return delegate?.editor?(editor: self, textView: textView, shouldInteractWith: URL, in: characterRange, interaction: interaction) ?? true
}
@objc
open func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return delegate?.editor?(editor: self, textView: textView, shouldInteractWith: textAttachment, in: characterRange, interaction: interaction) ?? true
}
}
*/
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment