Skip to content

Commit

Permalink
Added example iOS app and fixed bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew-Chen-Wang committed Mar 12, 2021
1 parent 19d7098 commit dae3419
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 8 deletions.
14 changes: 14 additions & 0 deletions ExampleRichEditorView/ExampleRichEditorView/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let vc = ViewController()
window!.rootViewController = vc
window!.makeKeyAndVisible()
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
47 changes: 47 additions & 0 deletions ExampleRichEditorView/ExampleRichEditorView/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Example</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
122 changes: 122 additions & 0 deletions ExampleRichEditorView/ExampleRichEditorView/ViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import UIKit
import RichEditorView

class ViewController: UIViewController {
let editorView = RichEditorView()
var prevText: String!
let toolbar = RichEditorToolbar()

override func viewDidLoad() {
super.viewDidLoad()
additionalSafeAreaInsets = .init(top: 6, left: 12, bottom: 0, right: 12)
editorView.translatesAutoresizingMaskIntoConstraints = false
editorView.delegate = self
editorView.editingEnabled = true
editorView.placeholder = "Press to start typing"
toolbar.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 44)
toolbar.options = RichEditorDefaultOption.all
toolbar.editor = editorView
toolbar.delegate = self
editorView.inputAccessoryView = toolbar
view.addSubview(editorView)
let sa = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
editorView.topAnchor.constraint(equalTo: sa.topAnchor),
editorView.leadingAnchor.constraint(equalTo: sa.leadingAnchor),
editorView.trailingAnchor.constraint(equalTo: sa.trailingAnchor),
editorView.bottomAnchor.constraint(equalTo: sa.bottomAnchor)
])
editorView.html = "What I'll usually do for focus and unfocus is similar to what Google Docs does. The insert link functionality is similar to Reddit's except I use a UIAlertController. There are some added and altered functionality like running your custom JS; you will just have to learn what goes on with this package, but it's a quick learn. <b>Good luck!</b> If you have any issues, Yoom will help out, so long as those issues are opened in this repo. Credits still go out to cjwirth and C. Bess" // setting the html must come AFTER the subview has been added. I'm not sure why, though. This could also not be the case after I ported this over to WKWebView
}
}

extension ViewController: RichEditorDelegate {
func richEditor(_ editor: RichEditorView, contentDidChange content: String) {
// This is meant to act as a text cap
if content.count > 40000 {
editor.html = prevText
} else {
prevText = content
}
}
}

extension ViewController: RichEditorToolbarDelegate {
func isURLValid(url: String?) -> Bool {
if(url?.hasPrefix("http://") ?? false || url?.hasPrefix("https://") ?? false) { return true }
return false
}

func richEditorToolbarInsertLink(_ toolbar: RichEditorToolbar) {
let alertController = UIAlertController(title: "Enter link and text", message: "You can leave the text empty to only show a clickable link", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Insert", style: .default) { (_) in
var link = alertController.textFields?[0].text
let text = alertController.textFields?[1].text
if link?.last != "/" { link = link! + "/" }
toolbar.editor?.insertLink(href: link!, text: text ?? link!)
self.editorView.focus()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
confirmAction.isEnabled = false
let linkPH = "Link (required)"
let txtPH = "Text (Clickable text that redirects to link)"
toolbar.editor?.hasRangeSelection(handler: { r in
if r == true {
alertController.addTextField { (textField) in
textField.placeholder = linkPH
toolbar.editor?.getSelectedHref(handler: { a in
if a?.last != "/" {
textField.text = nil
} else {
if self.isURLValid(url: a) == true {
textField.text = a
}
}
})
NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: OperationQueue.main) { (notification) in
if self.isURLValid(url: textField.text) == true {
confirmAction.isEnabled = textField.hasText
} else {
confirmAction.isEnabled = false
}
}
}
alertController.addTextField { (textField) in
textField.placeholder = txtPH
toolbar.editor?.getSelectedText(handler: { a in
textField.text = a
})
}
} else {
alertController.addTextField { (textField) in
textField.placeholder = linkPH
NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: OperationQueue.main) { (notification) in
if self.isURLValid(url: textField.text) == true {
confirmAction.isEnabled = textField.hasText
} else {
confirmAction.isEnabled = false
}
}
}
alertController.addTextField { (textField) in textField.placeholder = txtPH }
}
})
}


/*
// I'll first use getSelectedText and getSelectedHref functions to see if any selection has been made that we can autofill. Go to rich_editor.js for a deeper insight; be cautious since if there is a selection, then the selected text will be replaced.
var selectedText: String!
var selectedHref: String!
selectedText = editorView.getSelectedText()
selectedHref = editorView.getSelectedHref()
// The href is required to have a SLASH (/) at the end and a http:// or https:// prefix at the beginning. For my users, I use a UIAlertController (instead of Reddit's uiview). When a confirm action button is pressed, then I automatically check for these.
editorView.insertLink(href: "https://google.com/", text: "blah", title: nil)
// toolbar.editor?.insertLink(...) also works
// If you use a UIAlertController, then you must add editorView.focus(). This is due to the cursor being transferred from the editor view to the new controller which fill outs the links
// Remember this package is Google Docs style, not MarkDown or Reddit style like many other text editors.
*/
}
11 changes: 6 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@ let package = Package(
targets: ["RichEditorView"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "RichEditorView",
dependencies: []),
dependencies: [],
resources: [.process("Resources")]
),
.testTarget(
name: "RichEditorViewTests",
dependencies: ["RichEditorView"]),
dependencies: ["RichEditorView"],
resources: [.process("Resources")]
),
]
)
5 changes: 2 additions & 3 deletions Sources/RichEditorView/RichEditorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,8 @@ public class RichEditorWebView: WKWebView {
webView.scrollView.clipsToBounds = false
addSubview(webView)

if let filePath = Bundle(for: RichEditorView.self).path(forResource: "rich_editor", ofType: "html") {
let url = URL(fileURLWithPath: filePath, isDirectory: false)
webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
if let filePath = Bundle.module.url(forResource: "rich_editor", withExtension: "html") {
webView.loadFileURL(filePath, allowingReadAccessTo: filePath.deletingLastPathComponent())
}

tapRecognizer.addTarget(self, action: #selector(viewWasTapped))
Expand Down

0 comments on commit dae3419

Please sign in to comment.