What are these so withered and wild in their attire? " + anchor + "
that look not like the inhabitants of the Earth and yet are on't?"; 9 | var htmlWith2Links = "Blah? " + anchor + " " + anchor + " Blah
"; 10 | 11 | var tearDown = function() { 12 | RE.setHtml(''); 13 | }; 14 | 15 | /** 16 | This is the main and only public "method" 17 | **/ 18 | self.runTests = function() { 19 | var content = ""; 20 | for (var testName in tests) { 21 | tests[testName](); 22 | var log = 'Passed : ' + testName; 23 | console.log(log); 24 | content += log + "'); 265 | }; 266 | 267 | RE.insertHTML = function(html) { 268 | RE.restorerange(); 269 | document.execCommand('insertHTML', false, html); 270 | }; 271 | 272 | RE.insertLink = function(url, title) { 273 | RE.restorerange(); 274 | const sel = document.getSelection(); 275 | if (sel.toString().length !== 0) { 276 | if (sel.rangeCount) { 277 | let el = document.createElement('a'); 278 | el.setAttribute('href', url); 279 | el.setAttribute('title', title); 280 | 281 | let range = sel.getRangeAt(0).cloneRange(); 282 | range.surroundContents(el); 283 | sel.removeAllRanges(); 284 | sel.addRange(range); 285 | } 286 | } 287 | 288 | RE.sendInputCallback(); 289 | }; 290 | 291 | RE.prepareInsert = function() { 292 | RE.backuprange(); 293 | }; 294 | 295 | RE.backuprange = function() { 296 | const selection = window.getSelection(); 297 | if (selection.rangeCount === 0) { 298 | return; 299 | } 300 | 301 | let node = selection.anchorNode; 302 | if (node.nodeType === 3) { 303 | // use the parent, if text node 304 | node = node.parentNode; 305 | } 306 | 307 | const range = selection.getRangeAt(0); 308 | RE.currentSelection = { 309 | startContainer: range.startContainer, 310 | startOffset: range.startOffset, 311 | endContainer: range.endContainer, 312 | endOffset: range.endOffset, 313 | node, 314 | }; 315 | }; 316 | 317 | RE.addRangeToSelection = function(selection, range) { 318 | if (selection) { 319 | selection.removeAllRanges(); 320 | selection.addRange(range); 321 | } 322 | }; 323 | 324 | // Programatically select a DOM element 325 | RE.selectElementContents = function(el) { 326 | let range = document.createRange(); 327 | range.selectNodeContents(el); 328 | let sel = window.getSelection(); 329 | // this.createSelectionFromRange sel, range 330 | RE.addRangeToSelection(sel, range); 331 | }; 332 | 333 | RE.restorerange = function() { 334 | let selection = window.getSelection(); 335 | selection.removeAllRanges(); 336 | let range = document.createRange(); 337 | range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset); 338 | range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset); 339 | selection.addRange(range); 340 | }; 341 | 342 | RE.focus = function() { 343 | let range = document.createRange(); 344 | range.selectNodeContents(RE.editor); 345 | range.collapse(false); 346 | let selection = window.getSelection(); 347 | selection.removeAllRanges(); 348 | selection.addRange(range); 349 | RE.editor.focus(); 350 | }; 351 | 352 | RE.focusAtPoint = function(x, y) { 353 | const range = document.caretRangeFromPoint(x, y) || document.createRange(); 354 | const selection = window.getSelection(); 355 | selection.removeAllRanges(); 356 | selection.addRange(range); 357 | RE.editor.focus(); 358 | }; 359 | 360 | RE.blurFocus = function() { 361 | RE.editor.blur(); 362 | }; 363 | 364 | /** 365 | Recursively search element ancestors to find a element nodeName e.g. A 366 | **/ 367 | const _findNodeByNameInContainer = function(element, nodeName, rootElementId) { 368 | if (element.nodeName == nodeName) { 369 | return element; 370 | } else { 371 | if (element.id === rootElementId) { 372 | return null; 373 | } 374 | _findNodeByNameInContainer(element.parentElement, nodeName, rootElementId); 375 | } 376 | }; 377 | 378 | const isAnchorNode = function(node) { 379 | return ('A' == node.nodeName); 380 | }; 381 | 382 | RE.getAnchorTagsInNode = function(node) { 383 | let links = []; 384 | 385 | while (node.nextSibling !== null && node.nextSibling !== undefined) { 386 | node = node.nextSibling; 387 | if (isAnchorNode(node)) { 388 | links.push(node.getAttribute('href')); 389 | } 390 | } 391 | return links; 392 | }; 393 | 394 | RE.countAnchorTagsInNode = function(node) { 395 | return RE.getAnchorTagsInNode(node).length; 396 | }; 397 | 398 | /** 399 | * If the current selection's parent is an anchor tag, get the href. 400 | * @returns {string} 401 | */ 402 | RE.getSelectedHref = function() { 403 | let href = ''; 404 | let sel = window.getSelection(); 405 | if (!RE.rangeOrCaretSelectionExists()) { 406 | return null; 407 | } 408 | 409 | let tags = RE.getAnchorTagsInNode(sel.anchorNode); 410 | //if more than one link is there, return null 411 | if (tags.length > 1) { 412 | return null; 413 | } else if (tags.length == 1) { 414 | href = tags[0]; 415 | } else { 416 | let node = _findNodeByNameInContainer(sel.anchorNode.parentElement, 'A', 'editor'); 417 | href = node.href; 418 | } 419 | 420 | return (href ? href : null); 421 | }; 422 | 423 | // Returns the cursor position relative to its current position onscreen. 424 | // Can be negative if it is above what is visible 425 | RE.getRelativeCaretYPosition = function() { 426 | let y = 0; 427 | let sel = window.getSelection(); 428 | if (sel.rangeCount) { 429 | const range = sel.getRangeAt(0); 430 | const needsWorkAround = (range.startOffset == 0); 431 | /* Removing fixes bug when node name other than 'div' */ 432 | // && range.startContainer.nodeName.toLowerCase() == 'div'); 433 | if (needsWorkAround) { 434 | y = range.startContainer.offsetTop - window.pageYOffset; 435 | } else { 436 | if (range.getClientRects) { 437 | let rects = range.getClientRects(); 438 | if (rects.length > 0) { 439 | y = rects[0].top; 440 | } 441 | } 442 | } 443 | } 444 | 445 | return y; 446 | }; 447 | 448 | window.onload = function() { 449 | RE.callback('ready'); 450 | }; 451 | -------------------------------------------------------------------------------- /RichEditorView/Classes/RichEditorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RichEditor.swift 3 | // 4 | // Created by Caesar Wirth on 4/1/15. 5 | // Updated/Modernized by C. Bess on 9/18/19. 6 | // 7 | // Copyright (c) 2015 Caesar Wirth. All rights reserved. 8 | // 9 | 10 | import UIKit 11 | import WebKit 12 | 13 | /// The value we hold in order to be able to set the line height before the JS completely loads. 14 | private let DefaultInnerLineHeight: Int = 21 15 | 16 | /// RichEditorDelegate defines callbacks for the delegate of the RichEditorView 17 | @objc public protocol RichEditorDelegate: AnyObject { 18 | /// Called when the inner height of the text being displayed changes 19 | /// Can be used to update the UI 20 | @objc optional func richEditor(_ editor: RichEditorView, heightDidChange height: Int) 21 | 22 | /// Called whenever the content inside the view changes 23 | @objc optional func richEditor(_ editor: RichEditorView, contentDidChange content: String) 24 | 25 | /// Called when the rich editor starts editing 26 | @objc optional func richEditorTookFocus(_ editor: RichEditorView) 27 | 28 | /// Called when the rich editor stops editing or loses focus 29 | @objc optional func richEditorLostFocus(_ editor: RichEditorView) 30 | 31 | /// Called when the RichEditorView has become ready to receive input 32 | /// More concretely, is called when the internal WKWebView loads for the first time, and contentHTML is set 33 | @objc optional func richEditorDidLoad(_ editor: RichEditorView) 34 | 35 | /// Called when the internal WKWebView begins loading a URL that it does not know how to respond to 36 | /// For example, if there is an external link, and then the user taps it 37 | @objc optional func richEditor(_ editor: RichEditorView, shouldInteractWith url: URL) -> Bool 38 | 39 | /// Called when the internal WKWebView response to the external link and the `richEditor(_ editor: RichEditorView, shouldInteractWith url: URL)` should return true 40 | /// You should open the external link in this function. 41 | @objc optional func richEditor(_ editor: RichEditorView, interactWith url: URL) 42 | 43 | /// Called when custom actions are called by callbacks in the JS 44 | /// By default, this method is not used unless called by some custom JS that you add 45 | @objc optional func richEditor(_ editor: RichEditorView, handle action: String) 46 | } 47 | 48 | /// RichEditorView is a UIView that displays richly styled text, and allows it to be edited in a WYSIWYG fashion. 49 | @objcMembers open class RichEditorView: UIView, UIScrollViewDelegate, WKNavigationDelegate, UIGestureRecognizerDelegate { 50 | /// The delegate that will receive callbacks when certain actions are completed. 51 | open weak var delegate: RichEditorDelegate? 52 | 53 | /// Input accessory view to display over they keyboard. 54 | /// Defaults to nil 55 | open override var inputAccessoryView: UIView? { 56 | get { return webView.accessoryView } 57 | set { webView.accessoryView = newValue } 58 | } 59 | 60 | /// The internal WKWebView that is used to display the editor. 61 | open private(set) var webView: RichEditorWebView 62 | 63 | /// Whether or not scroll is enabled on the view. 64 | open var isScrollEnabled: Bool = true { 65 | didSet { 66 | webView.scrollView.isScrollEnabled = isScrollEnabled 67 | } 68 | } 69 | 70 | /// Whether or not to allow user input in the view. 71 | open var editingEnabled: Bool = false { 72 | didSet { contentEditable = editingEnabled } 73 | } 74 | 75 | /// The content HTML of the text being displayed. 76 | /// Is continually updated as the text is being edited. 77 | open private(set) var contentHTML: String = "" { 78 | didSet { 79 | if isReady { 80 | delegate?.richEditor?(self, contentDidChange: contentHTML) 81 | } 82 | } 83 | } 84 | 85 | /// The internal height of the text being displayed. 86 | /// Is continually being updated as the text is edited. 87 | open private(set) var editorHeight: Int = 0 { 88 | didSet { 89 | delegate?.richEditor?(self, heightDidChange: editorHeight) 90 | } 91 | } 92 | 93 | /// The line height of the editor. Defaults to 21. 94 | open private(set) var lineHeight: Int = DefaultInnerLineHeight { 95 | didSet { 96 | runJS("RE.setLineHeight('\(lineHeight)px')") 97 | } 98 | } 99 | 100 | /// Whether or not the editor DOM element has finished loading or not yet. 101 | private var isEditorLoaded = false 102 | 103 | /// Indicates if the editor should begin sending events to the delegate 104 | private var isReady = false 105 | 106 | /// Value that stores whether or not the content should be editable when the editor is loaded. 107 | /// Is basically `isEditingEnabled` before the editor is loaded. 108 | private var editingEnabledVar = true 109 | 110 | /// The HTML that is currently loaded in the editor view, if it is loaded. If it has not been loaded yet, it is the 111 | /// HTML that will be loaded into the editor view once it finishes initializing. 112 | public var html: String = "" { 113 | didSet { 114 | setHTML(html) 115 | } 116 | } 117 | 118 | /// Private variable that holds the placeholder text, so you can set the placeholder before the editor loads. 119 | private var placeholderText: String = "" 120 | /// The placeholder text that should be shown when there is no user input. 121 | open var placeholder: String { 122 | get { return placeholderText } 123 | set { 124 | placeholderText = newValue 125 | if isEditorLoaded { 126 | runJS("RE.setPlaceholderText('\(newValue.escaped)')") 127 | } 128 | } 129 | } 130 | 131 | // MARK: Initialization 132 | 133 | public override init(frame: CGRect) { 134 | webView = RichEditorWebView() 135 | super.init(frame: frame) 136 | setup() 137 | } 138 | 139 | required public init?(coder aDecoder: NSCoder) { 140 | webView = RichEditorWebView() 141 | super.init(coder: aDecoder) 142 | setup() 143 | } 144 | 145 | private func setup() { 146 | // configure webview 147 | webView.frame = bounds 148 | webView.navigationDelegate = self 149 | webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 150 | webView.configuration.dataDetectorTypes = WKDataDetectorTypes() 151 | webView.scrollView.isScrollEnabled = isScrollEnabled 152 | webView.scrollView.bounces = true 153 | webView.scrollView.delegate = self 154 | webView.scrollView.clipsToBounds = false 155 | addSubview(webView) 156 | 157 | reloadHTML(with: html) 158 | } 159 | 160 | /// Reloads the HTML for the editor. 161 | /// - parameter html: The HTML that will be loaded into the editor view once it finishes initializing. 162 | /// - parameter headerHTML: The header HTML that will be inserted after the default styles. 163 | /// - parameter footerHTML: The footer HTML that will be inserted after the default JavaScript. 164 | public func reloadHTML(with html: String, headerHTML: String = "", footerHTML: String = "") { 165 | guard let filePath = Bundle(for: RichEditorView.self).path(forResource: "rich_editor", ofType: "html") else { 166 | return 167 | } 168 | 169 | let readerHtmlTemplate = try! String(contentsOfFile: filePath) 170 | let fullHtml = readerHtmlTemplate 171 | .replacingOccurrences(of: "{{header}}", with: headerHTML) 172 | .replacingOccurrences(of: "{{footer}}", with: footerHTML) 173 | 174 | webView.loadHTMLString(fullHtml, baseURL: URL(fileURLWithPath: filePath, isDirectory: false).deletingLastPathComponent()) 175 | 176 | isEditorLoaded = false 177 | self.html = html 178 | } 179 | 180 | // MARK: - Rich Text Editing 181 | 182 | open func isEditingEnabled(handler: @escaping (Bool) -> Void) { 183 | isContentEditable(handler: handler) 184 | } 185 | 186 | private func getLineHeight(handler: @escaping (Int) -> Void) { 187 | if isEditorLoaded { 188 | runJS("RE.getLineHeight()") { r in 189 | if let r = Int(r) { 190 | handler(r) 191 | } else { 192 | handler(DefaultInnerLineHeight) 193 | } 194 | } 195 | } else { 196 | handler(DefaultInnerLineHeight) 197 | } 198 | } 199 | 200 | private func setHTML(_ value: String) { 201 | if isEditorLoaded { 202 | runJS("RE.setHtml('\(value.escaped)')") { _ in 203 | self.updateHeight() 204 | } 205 | } 206 | } 207 | 208 | /// The inner height of the editor div. 209 | /// Fetches it from JS every time, so might be slow! 210 | private func getClientHeight(handler: @escaping (Int) -> Void) { 211 | runJS("document.getElementById('editor').clientHeight") { r in 212 | if let r = Int(r) { 213 | handler(r) 214 | } else { 215 | handler(0) 216 | } 217 | } 218 | } 219 | 220 | public func getHtml(handler: @escaping (String) -> Void) { 221 | runJS("RE.getHtml()") { r in 222 | handler(r) 223 | } 224 | } 225 | 226 | /// Text representation of the data that has been input into the editor view, if it has been loaded. 227 | public func getText(handler: @escaping (String) -> Void) { 228 | runJS("RE.getText()") { r in 229 | handler(r) 230 | } 231 | } 232 | 233 | /// The href of the current selection, if the current selection's parent is an anchor tag. 234 | /// Will be nil if there is no href, or it is an empty string. 235 | public func getSelectedHref(handler: @escaping (String?) -> Void) { 236 | hasRangeSelection(handler: { r in 237 | if !r { 238 | handler(nil) 239 | return 240 | } 241 | self.runJS("RE.getSelectedHref()") { r in 242 | if r == "" { 243 | handler(nil) 244 | } else { 245 | handler(r) 246 | } 247 | } 248 | }) 249 | } 250 | 251 | /// Whether or not the selection has a type specifically of "Range". 252 | public func hasRangeSelection(handler: @escaping (Bool) -> Void) { 253 | runJS("RE.rangeSelectionExists()") { val in 254 | handler((val as NSString).boolValue) 255 | } 256 | } 257 | 258 | /// Whether or not the selection has a type specifically of "Range" or "Caret". 259 | public func hasRangeOrCaretSelection(handler: @escaping (Bool) -> Void) { 260 | runJS("RE.rangeOrCaretSelectionExists()") { val in 261 | handler((val as NSString).boolValue) 262 | } 263 | } 264 | 265 | // MARK: Methods 266 | 267 | public func removeFormat() { 268 | runJS("RE.removeFormat()") 269 | } 270 | 271 | public func setFontSize(_ size: Int) { 272 | runJS("RE.setFontSize('\(size)px')") 273 | } 274 | 275 | public func setEditorBackgroundColor(_ color: UIColor) { 276 | runJS("RE.setBackgroundColor('\(color.hex)')") 277 | } 278 | 279 | public func undo() { 280 | runJS("RE.undo()") 281 | } 282 | 283 | public func redo() { 284 | runJS("RE.redo()") 285 | } 286 | 287 | public func bold() { 288 | runJS("RE.setBold()") 289 | } 290 | 291 | public func italic() { 292 | runJS("RE.setItalic()") 293 | } 294 | 295 | // "superscript" is a keyword 296 | public func subscriptText() { 297 | runJS("RE.setSubscript()") 298 | } 299 | 300 | public func superscript() { 301 | runJS("RE.setSuperscript()") 302 | } 303 | 304 | public func strikethrough() { 305 | runJS("RE.setStrikeThrough()") 306 | } 307 | 308 | public func underline() { 309 | runJS("RE.setUnderline()") 310 | } 311 | 312 | private func getColorHex(with color: UIColor?) -> String { 313 | // if no color, then clear the color style css 314 | return color?.hex == nil ? "null" : "'\(color!.hex)'" 315 | } 316 | 317 | public func setTextColor(_ color: UIColor?) { 318 | runJS("RE.prepareInsert()") 319 | let color = getColorHex(with: color) 320 | runJS("RE.setTextColor(\(color))") 321 | } 322 | 323 | public func setEditorFontColor(_ color: UIColor) { 324 | runJS("RE.setBaseTextColor('\(color.hex)')") 325 | } 326 | 327 | public func setTextBackgroundColor(_ color: UIColor?) { 328 | runJS("RE.prepareInsert()") 329 | let color = getColorHex(with: color) 330 | runJS("RE.setTextBackgroundColor(\(color))") 331 | } 332 | 333 | public func header(_ h: Int) { 334 | runJS("RE.setHeading('\(h)')") 335 | } 336 | 337 | public func indent() { 338 | runJS("RE.setIndent()") 339 | } 340 | 341 | public func outdent() { 342 | runJS("RE.setOutdent()") 343 | } 344 | 345 | public func orderedList() { 346 | runJS("RE.setOrderedList()") 347 | } 348 | 349 | public func unorderedList() { 350 | runJS("RE.setUnorderedList()") 351 | } 352 | 353 | public func blockquote() { 354 | runJS("RE.setBlockquote()") 355 | } 356 | 357 | public func alignLeft() { 358 | runJS("RE.setJustifyLeft()") 359 | } 360 | 361 | public func alignCenter() { 362 | runJS("RE.setJustifyCenter()") 363 | } 364 | 365 | public func alignRight() { 366 | runJS("RE.setJustifyRight()") 367 | } 368 | 369 | public func insertImage(_ url: String, alt: String) { 370 | runJS("RE.prepareInsert()") 371 | runJS("RE.insertImage('\(url.escaped)', '\(alt.escaped)')") 372 | } 373 | 374 | public func insertLink(_ href: String, title: String) { 375 | runJS("RE.prepareInsert()") 376 | runJS("RE.insertLink('\(href.escaped)', '\(title.escaped)')") 377 | } 378 | 379 | public func focus() { 380 | runJS("RE.focus()") 381 | } 382 | 383 | public func focus(at: CGPoint) { 384 | runJS("RE.focusAtPoint(\(at.x), \(at.y))") 385 | } 386 | 387 | public func blur() { 388 | runJS("RE.blurFocus()") 389 | } 390 | 391 | /// Runs some JavaScript on the WKWebView and returns the result 392 | /// If there is no result, returns an empty string 393 | /// - parameter js: The JavaScript string to be run 394 | /// - returns: The result of the JavaScript that was run 395 | public func runJS(_ js: String, handler: ((String) -> Void)? = nil) { 396 | webView.evaluateJavaScript(js) { (result, error) in 397 | if let error = error { 398 | print("WKWebViewJavascriptBridge Error: \(String(describing: error)) - JS: \(js)") 399 | handler?("") 400 | return 401 | } 402 | 403 | guard let handler = handler else { 404 | return 405 | } 406 | 407 | if let resultInt = result as? Int { 408 | handler("\(resultInt)") 409 | return 410 | } 411 | 412 | if let resultBool = result as? Bool { 413 | handler(resultBool ? "true" : "false") 414 | return 415 | } 416 | 417 | if let resultStr = result as? String { 418 | handler(resultStr) 419 | return 420 | } 421 | 422 | // no result 423 | handler("") 424 | } 425 | } 426 | 427 | // MARK: - Delegate Methods 428 | 429 | // MARK: UIScrollViewDelegate 430 | 431 | public func scrollViewDidScroll(_ scrollView: UIScrollView) { 432 | // We use this to keep the scroll view from changing its offset when the keyboard comes up 433 | if !isScrollEnabled { 434 | scrollView.bounds = webView.bounds 435 | } 436 | } 437 | 438 | // MARK: WKWebViewDelegate 439 | 440 | public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { 441 | // empy 442 | } 443 | 444 | public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { 445 | // Handle pre-defined editor actions 446 | let callbackPrefix = "re-callback://" 447 | if navigationAction.request.url?.absoluteString.hasPrefix(callbackPrefix) == true { 448 | // When we get a callback, we need to fetch the command queue to run the commands 449 | // It comes in as a JSON array of commands that we need to parse 450 | runJS("RE.getCommandQueue()") { commands in 451 | if let data = commands.data(using: .utf8) { 452 | 453 | let jsonCommands: [String] 454 | do { 455 | jsonCommands = try JSONSerialization.jsonObject(with: data) as? [String] ?? [] 456 | } catch { 457 | jsonCommands = [] 458 | NSLog("RichEditorView: Failed to parse JSON Commands") 459 | } 460 | 461 | jsonCommands.forEach(self.performCommand) 462 | } 463 | } 464 | return decisionHandler(WKNavigationActionPolicy.cancel) 465 | } 466 | 467 | // User is tapping on a link, so we should react accordingly 468 | if navigationAction.navigationType == .linkActivated { 469 | if let url = navigationAction.request.url { 470 | if delegate?.richEditor?(self, shouldInteractWith: url) ?? false { 471 | delegate?.richEditor?(self, interactWith: url) 472 | return decisionHandler(WKNavigationActionPolicy.cancel) 473 | } 474 | } 475 | } 476 | 477 | return decisionHandler(WKNavigationActionPolicy.allow) 478 | } 479 | 480 | // MARK: UIGestureRecognizerDelegate 481 | 482 | /// Delegate method for our UITapGestureDelegate. 483 | /// Since the internal web view also has gesture recognizers, we have to make sure that we actually receive our taps. 484 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { 485 | return true 486 | } 487 | 488 | // MARK: - Private Implementation Details 489 | 490 | private var contentEditable: Bool = false { 491 | didSet { 492 | editingEnabledVar = contentEditable 493 | if isEditorLoaded { 494 | let value = (contentEditable ? "true" : "false") 495 | runJS("RE.editor.contentEditable = \(value)") 496 | } 497 | } 498 | } 499 | private func isContentEditable(handler: @escaping (Bool) -> Void) { 500 | if isEditorLoaded { 501 | // to get the "editable" value is a different property, than to disable it 502 | // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/contentEditable 503 | runJS("RE.editor.isContentEditable") { value in 504 | self.editingEnabledVar = Bool(value) ?? false 505 | } 506 | } 507 | } 508 | 509 | /// The position of the caret relative to the currently shown content. 510 | /// For example, if the cursor is directly at the top of what is visible, it will return 0. 511 | /// This also means that it will be negative if it is above what is currently visible. 512 | /// Can also return 0 if some sort of error occurs between JS and here. 513 | private func relativeCaretYPosition(handler: @escaping (Int) -> Void) { 514 | runJS("RE.getRelativeCaretYPosition()") { r in 515 | handler(Int(r) ?? 0) 516 | } 517 | } 518 | 519 | private func updateHeight() { 520 | runJS("document.getElementById('editor').clientHeight") { heightString in 521 | let height = Int(heightString) ?? 0 522 | if self.editorHeight != height { 523 | self.editorHeight = height 524 | } 525 | } 526 | } 527 | 528 | /// Scrolls the editor to a position where the caret is visible. 529 | /// Called repeatedly to make sure the caret is always visible when inputting text. 530 | /// Works only if the `lineHeight` of the editor is available. 531 | private func scrollCaretToVisible() { 532 | let scrollView = self.webView.scrollView 533 | 534 | getClientHeight(handler: { clientHeight in 535 | let contentHeight = clientHeight > 0 ? CGFloat(clientHeight) : scrollView.frame.height 536 | scrollView.contentSize = CGSize(width: scrollView.frame.width, height: contentHeight) 537 | 538 | // XXX: Maybe find a better way to get the cursor height 539 | self.getLineHeight(handler: { lh in 540 | let lineHeight = CGFloat(lh) 541 | let cursorHeight = lineHeight - 4 542 | self.relativeCaretYPosition(handler: { r in 543 | let visiblePosition = CGFloat(r) 544 | var offset: CGPoint? 545 | 546 | if visiblePosition + cursorHeight > scrollView.bounds.size.height { 547 | // Visible caret position goes further than our bounds 548 | offset = CGPoint(x: 0, y: (visiblePosition + lineHeight) - scrollView.bounds.height + scrollView.contentOffset.y) 549 | } else if visiblePosition < 0 { 550 | // Visible caret position is above what is currently visible 551 | var amount = scrollView.contentOffset.y + visiblePosition 552 | amount = amount < 0 ? 0 : amount 553 | offset = CGPoint(x: scrollView.contentOffset.x, y: amount) 554 | } 555 | 556 | if let offset = offset { 557 | scrollView.setContentOffset(offset, animated: true) 558 | } 559 | }) 560 | }) 561 | }) 562 | } 563 | 564 | /// Called when actions are received from JavaScript 565 | /// - parameter method: String with the name of the method and optional parameters that were passed in 566 | private func performCommand(_ method: String) { 567 | if method.hasPrefix("ready") { 568 | // If loading for the first time, we have to set the content HTML to be displayed 569 | if !isEditorLoaded { 570 | isEditorLoaded = true 571 | setHTML(html) 572 | contentHTML = html 573 | contentEditable = editingEnabledVar 574 | placeholder = placeholderText 575 | lineHeight = DefaultInnerLineHeight 576 | 577 | delegate?.richEditorDidLoad?(self) 578 | isReady = true 579 | } 580 | updateHeight() 581 | } else if method.hasPrefix("input") { 582 | scrollCaretToVisible() 583 | runJS("RE.getHtml()") { content in 584 | self.contentHTML = content 585 | self.updateHeight() 586 | } 587 | } else if method.hasPrefix("updateHeight") { 588 | updateHeight() 589 | } else if method.hasPrefix("focus") { 590 | delegate?.richEditorTookFocus?(self) 591 | } else if method.hasPrefix("blur") { 592 | delegate?.richEditorLostFocus?(self) 593 | } else if method.hasPrefix("action/") { 594 | runJS("RE.getHtml()") { content in 595 | self.contentHTML = content 596 | 597 | // If there are any custom actions being called 598 | // We need to tell the delegate about it 599 | let actionPrefix = "action/" 600 | let range = method.range(of: actionPrefix)! 601 | let action = method.replacingCharacters(in: range, with: "") 602 | 603 | self.delegate?.richEditor?(self, handle: action) 604 | } 605 | } 606 | } 607 | 608 | // MARK: - Responder Handling 609 | 610 | override open func becomeFirstResponder() -> Bool { 611 | if !webView.isFirstResponder { 612 | focus() 613 | return true 614 | } else { 615 | return false 616 | } 617 | } 618 | 619 | open override func resignFirstResponder() -> Bool { 620 | blur() 621 | return true 622 | } 623 | 624 | } 625 | -------------------------------------------------------------------------------- /RichEditorViewSample/RichEditorViewSample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0CCBA517EA66E1DE61C19F69 /* Pods_RichEditorViewSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CA6B4DFCB1BCDED9BE91A70 /* Pods_RichEditorViewSample.framework */; }; 11 | 39883B491AD0DC270031FD16 /* KeyboardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39883B481AD0DC270031FD16 /* KeyboardManager.swift */; }; 12 | 39BBCFB01AD0CC7A00A450D2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BBCFAF1AD0CC7A00A450D2 /* AppDelegate.swift */; }; 13 | 39BBCFB21AD0CC7A00A450D2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BBCFB11AD0CC7A00A450D2 /* ViewController.swift */; }; 14 | 39BBCFB51AD0CC7A00A450D2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39BBCFB31AD0CC7A00A450D2 /* Main.storyboard */; }; 15 | 39BBCFB71AD0CC7A00A450D2 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39BBCFB61AD0CC7A00A450D2 /* Images.xcassets */; }; 16 | 39BBCFBA1AD0CC7A00A450D2 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 39BBCFB81AD0CC7A00A450D2 /* LaunchScreen.xib */; }; 17 | 39BBCFC61AD0CC7A00A450D2 /* RichEditorViewSampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BBCFC51AD0CC7A00A450D2 /* RichEditorViewSampleTests.swift */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | 39BBCFC01AD0CC7A00A450D2 /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = 39BBCFA21AD0CC7A00A450D2 /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = 39BBCFA91AD0CC7A00A450D2; 26 | remoteInfo = RichEditorViewSample; 27 | }; 28 | /* End PBXContainerItemProxy section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 1CA6B4DFCB1BCDED9BE91A70 /* Pods_RichEditorViewSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RichEditorViewSample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | 3912A4531B966C34005E41FA /* RichEditorViewSample-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RichEditorViewSample-Bridging-Header.h"; sourceTree = ""; }; 33 | 39883B481AD0DC270031FD16 /* KeyboardManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardManager.swift; sourceTree = " "; }; 34 | 39BBCFAA1AD0CC7A00A450D2 /* RichEditorViewSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RichEditorViewSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 39BBCFAE1AD0CC7A00A450D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = " "; }; 36 | 39BBCFAF1AD0CC7A00A450D2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = " "; }; 37 | 39BBCFB11AD0CC7A00A450D2 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = " "; }; 38 | 39BBCFB41AD0CC7A00A450D2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = " "; }; 39 | 39BBCFB61AD0CC7A00A450D2 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = " "; }; 40 | 39BBCFB91AD0CC7A00A450D2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = " "; }; 41 | 39BBCFBF1AD0CC7A00A450D2 /* RichEditorViewSampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RichEditorViewSampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 39BBCFC41AD0CC7A00A450D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = " "; }; 43 | 39BBCFC51AD0CC7A00A450D2 /* RichEditorViewSampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RichEditorViewSampleTests.swift; sourceTree = " "; }; 44 | 39BBCFD01AD0CD4700A450D2 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = " "; }; 45 | 39BBCFD11AD0CD4700A450D2 /* RichEditorView.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = RichEditorView.podspec; path = ../RichEditorView.podspec; sourceTree = " "; }; 46 | 996D5C7A9F5BD7BF325118C8 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 9AF21FE45EA87DF1498534F6 /* Pods-RichEditorViewSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RichEditorViewSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-RichEditorViewSample/Pods-RichEditorViewSample.release.xcconfig"; sourceTree = " "; }; 48 | C6E2423BEEB12C12D184ACDD /* Pods-RichEditorViewSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RichEditorViewSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RichEditorViewSample/Pods-RichEditorViewSample.debug.xcconfig"; sourceTree = " "; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | 39BBCFA71AD0CC7A00A450D2 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | 0CCBA517EA66E1DE61C19F69 /* Pods_RichEditorViewSample.framework in Frameworks */, 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | 39BBCFBC1AD0CC7A00A450D2 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | 106F1EB9E1302E9C38A73C48 /* Frameworks */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 996D5C7A9F5BD7BF325118C8 /* Pods.framework */, 74 | 1CA6B4DFCB1BCDED9BE91A70 /* Pods_RichEditorViewSample.framework */, 75 | ); 76 | name = Frameworks; 77 | sourceTree = " "; 78 | }; 79 | 39BBCFA11AD0CC7A00A450D2 = { 80 | isa = PBXGroup; 81 | children = ( 82 | 39BBCFCF1AD0CD3500A450D2 /* Pod Metadata */, 83 | 39BBCFAC1AD0CC7A00A450D2 /* RichEditorViewSample */, 84 | 39BBCFC21AD0CC7A00A450D2 /* RichEditorViewSampleTests */, 85 | 39BBCFAB1AD0CC7A00A450D2 /* Products */, 86 | 106F1EB9E1302E9C38A73C48 /* Frameworks */, 87 | 6B97E8B97DF9831B87D18089 /* Pods */, 88 | ); 89 | sourceTree = " "; 90 | }; 91 | 39BBCFAB1AD0CC7A00A450D2 /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 39BBCFAA1AD0CC7A00A450D2 /* RichEditorViewSample.app */, 95 | 39BBCFBF1AD0CC7A00A450D2 /* RichEditorViewSampleTests.xctest */, 96 | ); 97 | name = Products; 98 | sourceTree = " "; 99 | }; 100 | 39BBCFAC1AD0CC7A00A450D2 /* RichEditorViewSample */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 39BBCFAF1AD0CC7A00A450D2 /* AppDelegate.swift */, 104 | 39BBCFB11AD0CC7A00A450D2 /* ViewController.swift */, 105 | 39BBCFB31AD0CC7A00A450D2 /* Main.storyboard */, 106 | 39BBCFB61AD0CC7A00A450D2 /* Images.xcassets */, 107 | 39BBCFB81AD0CC7A00A450D2 /* LaunchScreen.xib */, 108 | 39BBCFAD1AD0CC7A00A450D2 /* Supporting Files */, 109 | 39883B481AD0DC270031FD16 /* KeyboardManager.swift */, 110 | 3912A4531B966C34005E41FA /* RichEditorViewSample-Bridging-Header.h */, 111 | ); 112 | path = RichEditorViewSample; 113 | sourceTree = " "; 114 | }; 115 | 39BBCFAD1AD0CC7A00A450D2 /* Supporting Files */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 39BBCFAE1AD0CC7A00A450D2 /* Info.plist */, 119 | ); 120 | name = "Supporting Files"; 121 | sourceTree = " "; 122 | }; 123 | 39BBCFC21AD0CC7A00A450D2 /* RichEditorViewSampleTests */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 39BBCFC51AD0CC7A00A450D2 /* RichEditorViewSampleTests.swift */, 127 | 39BBCFC31AD0CC7A00A450D2 /* Supporting Files */, 128 | ); 129 | path = RichEditorViewSampleTests; 130 | sourceTree = " "; 131 | }; 132 | 39BBCFC31AD0CC7A00A450D2 /* Supporting Files */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 39BBCFC41AD0CC7A00A450D2 /* Info.plist */, 136 | ); 137 | name = "Supporting Files"; 138 | sourceTree = " "; 139 | }; 140 | 39BBCFCF1AD0CD3500A450D2 /* Pod Metadata */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 39BBCFD01AD0CD4700A450D2 /* README.md */, 144 | 39BBCFD11AD0CD4700A450D2 /* RichEditorView.podspec */, 145 | ); 146 | name = "Pod Metadata"; 147 | sourceTree = " "; 148 | }; 149 | 6B97E8B97DF9831B87D18089 /* Pods */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | C6E2423BEEB12C12D184ACDD /* Pods-RichEditorViewSample.debug.xcconfig */, 153 | 9AF21FE45EA87DF1498534F6 /* Pods-RichEditorViewSample.release.xcconfig */, 154 | ); 155 | name = Pods; 156 | sourceTree = " "; 157 | }; 158 | /* End PBXGroup section */ 159 | 160 | /* Begin PBXNativeTarget section */ 161 | 39BBCFA91AD0CC7A00A450D2 /* RichEditorViewSample */ = { 162 | isa = PBXNativeTarget; 163 | buildConfigurationList = 39BBCFC91AD0CC7A00A450D2 /* Build configuration list for PBXNativeTarget "RichEditorViewSample" */; 164 | buildPhases = ( 165 | 4E74B098CF14DF0631DC2B86 /* [CP] Check Pods Manifest.lock */, 166 | 39BBCFA61AD0CC7A00A450D2 /* Sources */, 167 | 39BBCFA71AD0CC7A00A450D2 /* Frameworks */, 168 | 39BBCFA81AD0CC7A00A450D2 /* Resources */, 169 | 912CF3E5DB1B7FACFF97C026 /* [CP] Embed Pods Frameworks */, 170 | ); 171 | buildRules = ( 172 | ); 173 | dependencies = ( 174 | ); 175 | name = RichEditorViewSample; 176 | productName = RichEditorViewSample; 177 | productReference = 39BBCFAA1AD0CC7A00A450D2 /* RichEditorViewSample.app */; 178 | productType = "com.apple.product-type.application"; 179 | }; 180 | 39BBCFBE1AD0CC7A00A450D2 /* RichEditorViewSampleTests */ = { 181 | isa = PBXNativeTarget; 182 | buildConfigurationList = 39BBCFCC1AD0CC7A00A450D2 /* Build configuration list for PBXNativeTarget "RichEditorViewSampleTests" */; 183 | buildPhases = ( 184 | 39BBCFBB1AD0CC7A00A450D2 /* Sources */, 185 | 39BBCFBC1AD0CC7A00A450D2 /* Frameworks */, 186 | 39BBCFBD1AD0CC7A00A450D2 /* Resources */, 187 | ); 188 | buildRules = ( 189 | ); 190 | dependencies = ( 191 | 39BBCFC11AD0CC7A00A450D2 /* PBXTargetDependency */, 192 | ); 193 | name = RichEditorViewSampleTests; 194 | productName = RichEditorViewSampleTests; 195 | productReference = 39BBCFBF1AD0CC7A00A450D2 /* RichEditorViewSampleTests.xctest */; 196 | productType = "com.apple.product-type.bundle.unit-test"; 197 | }; 198 | /* End PBXNativeTarget section */ 199 | 200 | /* Begin PBXProject section */ 201 | 39BBCFA21AD0CC7A00A450D2 /* Project object */ = { 202 | isa = PBXProject; 203 | attributes = { 204 | LastSwiftUpdateCheck = 0700; 205 | LastUpgradeCheck = 1200; 206 | ORGANIZATIONNAME = "Caesar Wirth"; 207 | TargetAttributes = { 208 | 39BBCFA91AD0CC7A00A450D2 = { 209 | CreatedOnToolsVersion = 6.2; 210 | DevelopmentTeam = 89MZF7SG7M; 211 | LastSwiftMigration = ""; 212 | }; 213 | 39BBCFBE1AD0CC7A00A450D2 = { 214 | CreatedOnToolsVersion = 6.2; 215 | LastSwiftMigration = ""; 216 | TestTargetID = 39BBCFA91AD0CC7A00A450D2; 217 | }; 218 | }; 219 | }; 220 | buildConfigurationList = 39BBCFA51AD0CC7A00A450D2 /* Build configuration list for PBXProject "RichEditorViewSample" */; 221 | compatibilityVersion = "Xcode 3.2"; 222 | developmentRegion = en; 223 | hasScannedForEncodings = 0; 224 | knownRegions = ( 225 | en, 226 | Base, 227 | ); 228 | mainGroup = 39BBCFA11AD0CC7A00A450D2; 229 | productRefGroup = 39BBCFAB1AD0CC7A00A450D2 /* Products */; 230 | projectDirPath = ""; 231 | projectRoot = ""; 232 | targets = ( 233 | 39BBCFA91AD0CC7A00A450D2 /* RichEditorViewSample */, 234 | 39BBCFBE1AD0CC7A00A450D2 /* RichEditorViewSampleTests */, 235 | ); 236 | }; 237 | /* End PBXProject section */ 238 | 239 | /* Begin PBXResourcesBuildPhase section */ 240 | 39BBCFA81AD0CC7A00A450D2 /* Resources */ = { 241 | isa = PBXResourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 39BBCFB51AD0CC7A00A450D2 /* Main.storyboard in Resources */, 245 | 39BBCFBA1AD0CC7A00A450D2 /* LaunchScreen.xib in Resources */, 246 | 39BBCFB71AD0CC7A00A450D2 /* Images.xcassets in Resources */, 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | 39BBCFBD1AD0CC7A00A450D2 /* Resources */ = { 251 | isa = PBXResourcesBuildPhase; 252 | buildActionMask = 2147483647; 253 | files = ( 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | }; 257 | /* End PBXResourcesBuildPhase section */ 258 | 259 | /* Begin PBXShellScriptBuildPhase section */ 260 | 4E74B098CF14DF0631DC2B86 /* [CP] Check Pods Manifest.lock */ = { 261 | isa = PBXShellScriptBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | ); 265 | inputPaths = ( 266 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 267 | "${PODS_ROOT}/Manifest.lock", 268 | ); 269 | name = "[CP] Check Pods Manifest.lock"; 270 | outputPaths = ( 271 | "$(DERIVED_FILE_DIR)/Pods-RichEditorViewSample-checkManifestLockResult.txt", 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | shellPath = /bin/sh; 275 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 276 | showEnvVarsInLog = 0; 277 | }; 278 | 912CF3E5DB1B7FACFF97C026 /* [CP] Embed Pods Frameworks */ = { 279 | isa = PBXShellScriptBuildPhase; 280 | buildActionMask = 2147483647; 281 | files = ( 282 | ); 283 | inputPaths = ( 284 | "${PODS_ROOT}/Target Support Files/Pods-RichEditorViewSample/Pods-RichEditorViewSample-frameworks.sh", 285 | "${BUILT_PRODUCTS_DIR}/RichEditorView/RichEditorView.framework", 286 | ); 287 | name = "[CP] Embed Pods Frameworks"; 288 | outputPaths = ( 289 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RichEditorView.framework", 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | shellPath = /bin/sh; 293 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RichEditorViewSample/Pods-RichEditorViewSample-frameworks.sh\"\n"; 294 | showEnvVarsInLog = 0; 295 | }; 296 | /* End PBXShellScriptBuildPhase section */ 297 | 298 | /* Begin PBXSourcesBuildPhase section */ 299 | 39BBCFA61AD0CC7A00A450D2 /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 39883B491AD0DC270031FD16 /* KeyboardManager.swift in Sources */, 304 | 39BBCFB21AD0CC7A00A450D2 /* ViewController.swift in Sources */, 305 | 39BBCFB01AD0CC7A00A450D2 /* AppDelegate.swift in Sources */, 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | 39BBCFBB1AD0CC7A00A450D2 /* Sources */ = { 310 | isa = PBXSourcesBuildPhase; 311 | buildActionMask = 2147483647; 312 | files = ( 313 | 39BBCFC61AD0CC7A00A450D2 /* RichEditorViewSampleTests.swift in Sources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | /* End PBXSourcesBuildPhase section */ 318 | 319 | /* Begin PBXTargetDependency section */ 320 | 39BBCFC11AD0CC7A00A450D2 /* PBXTargetDependency */ = { 321 | isa = PBXTargetDependency; 322 | target = 39BBCFA91AD0CC7A00A450D2 /* RichEditorViewSample */; 323 | targetProxy = 39BBCFC01AD0CC7A00A450D2 /* PBXContainerItemProxy */; 324 | }; 325 | /* End PBXTargetDependency section */ 326 | 327 | /* Begin PBXVariantGroup section */ 328 | 39BBCFB31AD0CC7A00A450D2 /* Main.storyboard */ = { 329 | isa = PBXVariantGroup; 330 | children = ( 331 | 39BBCFB41AD0CC7A00A450D2 /* Base */, 332 | ); 333 | name = Main.storyboard; 334 | sourceTree = " "; 335 | }; 336 | 39BBCFB81AD0CC7A00A450D2 /* LaunchScreen.xib */ = { 337 | isa = PBXVariantGroup; 338 | children = ( 339 | 39BBCFB91AD0CC7A00A450D2 /* Base */, 340 | ); 341 | name = LaunchScreen.xib; 342 | sourceTree = " "; 343 | }; 344 | /* End PBXVariantGroup section */ 345 | 346 | /* Begin XCBuildConfiguration section */ 347 | 39BBCFC71AD0CC7A00A450D2 /* Debug */ = { 348 | isa = XCBuildConfiguration; 349 | buildSettings = { 350 | ALWAYS_SEARCH_USER_PATHS = NO; 351 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 352 | CLANG_CXX_LIBRARY = "libc++"; 353 | CLANG_ENABLE_MODULES = YES; 354 | CLANG_ENABLE_OBJC_ARC = YES; 355 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 356 | CLANG_WARN_BOOL_CONVERSION = YES; 357 | CLANG_WARN_COMMA = YES; 358 | CLANG_WARN_CONSTANT_CONVERSION = YES; 359 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 360 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 361 | CLANG_WARN_EMPTY_BODY = YES; 362 | CLANG_WARN_ENUM_CONVERSION = YES; 363 | CLANG_WARN_INFINITE_RECURSION = YES; 364 | CLANG_WARN_INT_CONVERSION = YES; 365 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 366 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 367 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 368 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 369 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 370 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 371 | CLANG_WARN_STRICT_PROTOTYPES = YES; 372 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 373 | CLANG_WARN_UNREACHABLE_CODE = YES; 374 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 375 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 376 | COPY_PHASE_STRIP = NO; 377 | ENABLE_STRICT_OBJC_MSGSEND = YES; 378 | ENABLE_TESTABILITY = YES; 379 | GCC_C_LANGUAGE_STANDARD = gnu99; 380 | GCC_DYNAMIC_NO_PIC = NO; 381 | GCC_NO_COMMON_BLOCKS = YES; 382 | GCC_OPTIMIZATION_LEVEL = 0; 383 | GCC_PREPROCESSOR_DEFINITIONS = ( 384 | "DEBUG=1", 385 | "$(inherited)", 386 | ); 387 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 388 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 389 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 390 | GCC_WARN_UNDECLARED_SELECTOR = YES; 391 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 392 | GCC_WARN_UNUSED_FUNCTION = YES; 393 | GCC_WARN_UNUSED_VARIABLE = YES; 394 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 395 | MTL_ENABLE_DEBUG_INFO = YES; 396 | ONLY_ACTIVE_ARCH = YES; 397 | SDKROOT = iphoneos; 398 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 399 | TARGETED_DEVICE_FAMILY = "1,2"; 400 | }; 401 | name = Debug; 402 | }; 403 | 39BBCFC81AD0CC7A00A450D2 /* Release */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ALWAYS_SEARCH_USER_PATHS = NO; 407 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 408 | CLANG_CXX_LIBRARY = "libc++"; 409 | CLANG_ENABLE_MODULES = YES; 410 | CLANG_ENABLE_OBJC_ARC = YES; 411 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 412 | CLANG_WARN_BOOL_CONVERSION = YES; 413 | CLANG_WARN_COMMA = YES; 414 | CLANG_WARN_CONSTANT_CONVERSION = YES; 415 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 416 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 417 | CLANG_WARN_EMPTY_BODY = YES; 418 | CLANG_WARN_ENUM_CONVERSION = YES; 419 | CLANG_WARN_INFINITE_RECURSION = YES; 420 | CLANG_WARN_INT_CONVERSION = YES; 421 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 422 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 423 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 424 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 425 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 426 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 427 | CLANG_WARN_STRICT_PROTOTYPES = YES; 428 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 429 | CLANG_WARN_UNREACHABLE_CODE = YES; 430 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 431 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 432 | COPY_PHASE_STRIP = NO; 433 | ENABLE_NS_ASSERTIONS = NO; 434 | ENABLE_STRICT_OBJC_MSGSEND = YES; 435 | GCC_C_LANGUAGE_STANDARD = gnu99; 436 | GCC_NO_COMMON_BLOCKS = YES; 437 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 438 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 439 | GCC_WARN_UNDECLARED_SELECTOR = YES; 440 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 441 | GCC_WARN_UNUSED_FUNCTION = YES; 442 | GCC_WARN_UNUSED_VARIABLE = YES; 443 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 444 | MTL_ENABLE_DEBUG_INFO = NO; 445 | SDKROOT = iphoneos; 446 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 447 | TARGETED_DEVICE_FAMILY = "1,2"; 448 | VALIDATE_PRODUCT = YES; 449 | }; 450 | name = Release; 451 | }; 452 | 39BBCFCA1AD0CC7A00A450D2 /* Debug */ = { 453 | isa = XCBuildConfiguration; 454 | baseConfigurationReference = C6E2423BEEB12C12D184ACDD /* Pods-RichEditorViewSample.debug.xcconfig */; 455 | buildSettings = { 456 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 457 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 458 | CLANG_ENABLE_MODULES = YES; 459 | DEVELOPMENT_TEAM = 89MZF7SG7M; 460 | INFOPLIST_FILE = RichEditorViewSample/Info.plist; 461 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 462 | PRODUCT_BUNDLE_IDENTIFIER = com.cbess.RichEditorViewSample; 463 | PRODUCT_NAME = "$(TARGET_NAME)"; 464 | SWIFT_OBJC_BRIDGING_HEADER = "RichEditorViewSample/RichEditorViewSample-Bridging-Header.h"; 465 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 466 | SWIFT_VERSION = 5.0; 467 | }; 468 | name = Debug; 469 | }; 470 | 39BBCFCB1AD0CC7A00A450D2 /* Release */ = { 471 | isa = XCBuildConfiguration; 472 | baseConfigurationReference = 9AF21FE45EA87DF1498534F6 /* Pods-RichEditorViewSample.release.xcconfig */; 473 | buildSettings = { 474 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 475 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 476 | CLANG_ENABLE_MODULES = YES; 477 | DEVELOPMENT_TEAM = 89MZF7SG7M; 478 | INFOPLIST_FILE = RichEditorViewSample/Info.plist; 479 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 480 | PRODUCT_BUNDLE_IDENTIFIER = com.cbess.RichEditorViewSample; 481 | PRODUCT_NAME = "$(TARGET_NAME)"; 482 | SWIFT_OBJC_BRIDGING_HEADER = "RichEditorViewSample/RichEditorViewSample-Bridging-Header.h"; 483 | SWIFT_VERSION = 5.0; 484 | }; 485 | name = Release; 486 | }; 487 | 39BBCFCD1AD0CC7A00A450D2 /* Debug */ = { 488 | isa = XCBuildConfiguration; 489 | buildSettings = { 490 | BUNDLE_LOADER = "$(TEST_HOST)"; 491 | GCC_PREPROCESSOR_DEFINITIONS = ( 492 | "DEBUG=1", 493 | "$(inherited)", 494 | ); 495 | INFOPLIST_FILE = RichEditorViewSampleTests/Info.plist; 496 | PRODUCT_BUNDLE_IDENTIFIER = "com.cjwirth.$(PRODUCT_NAME:rfc1034identifier)"; 497 | PRODUCT_NAME = "$(TARGET_NAME)"; 498 | SWIFT_VERSION = 5.0; 499 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RichEditorViewSample.app/RichEditorViewSample"; 500 | }; 501 | name = Debug; 502 | }; 503 | 39BBCFCE1AD0CC7A00A450D2 /* Release */ = { 504 | isa = XCBuildConfiguration; 505 | buildSettings = { 506 | BUNDLE_LOADER = "$(TEST_HOST)"; 507 | INFOPLIST_FILE = RichEditorViewSampleTests/Info.plist; 508 | PRODUCT_BUNDLE_IDENTIFIER = "com.cjwirth.$(PRODUCT_NAME:rfc1034identifier)"; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | SWIFT_VERSION = 5.0; 511 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RichEditorViewSample.app/RichEditorViewSample"; 512 | }; 513 | name = Release; 514 | }; 515 | /* End XCBuildConfiguration section */ 516 | 517 | /* Begin XCConfigurationList section */ 518 | 39BBCFA51AD0CC7A00A450D2 /* Build configuration list for PBXProject "RichEditorViewSample" */ = { 519 | isa = XCConfigurationList; 520 | buildConfigurations = ( 521 | 39BBCFC71AD0CC7A00A450D2 /* Debug */, 522 | 39BBCFC81AD0CC7A00A450D2 /* Release */, 523 | ); 524 | defaultConfigurationIsVisible = 0; 525 | defaultConfigurationName = Release; 526 | }; 527 | 39BBCFC91AD0CC7A00A450D2 /* Build configuration list for PBXNativeTarget "RichEditorViewSample" */ = { 528 | isa = XCConfigurationList; 529 | buildConfigurations = ( 530 | 39BBCFCA1AD0CC7A00A450D2 /* Debug */, 531 | 39BBCFCB1AD0CC7A00A450D2 /* Release */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | 39BBCFCC1AD0CC7A00A450D2 /* Build configuration list for PBXNativeTarget "RichEditorViewSampleTests" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | 39BBCFCD1AD0CC7A00A450D2 /* Debug */, 540 | 39BBCFCE1AD0CC7A00A450D2 /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | /* End XCConfigurationList section */ 546 | }; 547 | rootObject = 39BBCFA21AD0CC7A00A450D2 /* Project object */; 548 | } 549 | -------------------------------------------------------------------------------- /RichEditorView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 947A71A11C0F9DED00BDF9FC /* UIView+Responder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 947A71A01C0F9DED00BDF9FC /* UIView+Responder.swift */; }; 11 | FBA6AAFF1AD3EC9F00721644 /* RichEditorView.h in Headers */ = {isa = PBXBuildFile; fileRef = FBA6AAFE1AD3EC9F00721644 /* RichEditorView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | FBA6AB051AD3EC9F00721644 /* RichEditorView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBA6AAF91AD3EC9F00721644 /* RichEditorView.framework */; }; 13 | FBA6AB0C1AD3EC9F00721644 /* RichEditorViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBA6AB0B1AD3EC9F00721644 /* RichEditorViewTests.swift */; }; 14 | FBA6AB4F1AD3ED2D00721644 /* normalize.css in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB191AD3ED2D00721644 /* normalize.css */; }; 15 | FBA6AB501AD3ED2D00721644 /* rich_editor.html in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB1A1AD3ED2D00721644 /* rich_editor.html */; }; 16 | FBA6AB511AD3ED2D00721644 /* rich_editor.js in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB1B1AD3ED2D00721644 /* rich_editor.js */; }; 17 | FBA6AB521AD3ED2D00721644 /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB1C1AD3ED2D00721644 /* style.css */; }; 18 | FBA6AB531AD3ED2D00721644 /* bg_color.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB1E1AD3ED2D00721644 /* bg_color.png */; }; 19 | FBA6AB541AD3ED2D00721644 /* bg_color@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB1F1AD3ED2D00721644 /* bg_color@2x.png */; }; 20 | FBA6AB551AD3ED2D00721644 /* bold.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB201AD3ED2D00721644 /* bold.png */; }; 21 | FBA6AB561AD3ED2D00721644 /* bold@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB211AD3ED2D00721644 /* bold@2x.png */; }; 22 | FBA6AB571AD3ED2D00721644 /* clear.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB221AD3ED2D00721644 /* clear.png */; }; 23 | FBA6AB581AD3ED2D00721644 /* clear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB231AD3ED2D00721644 /* clear@2x.png */; }; 24 | FBA6AB591AD3ED2D00721644 /* h1.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB241AD3ED2D00721644 /* h1.png */; }; 25 | FBA6AB5A1AD3ED2D00721644 /* h1@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB251AD3ED2D00721644 /* h1@2x.png */; }; 26 | FBA6AB5B1AD3ED2D00721644 /* h2.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB261AD3ED2D00721644 /* h2.png */; }; 27 | FBA6AB5C1AD3ED2D00721644 /* h2@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB271AD3ED2D00721644 /* h2@2x.png */; }; 28 | FBA6AB5D1AD3ED2D00721644 /* h3.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB281AD3ED2D00721644 /* h3.png */; }; 29 | FBA6AB5E1AD3ED2D00721644 /* h3@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB291AD3ED2D00721644 /* h3@2x.png */; }; 30 | FBA6AB5F1AD3ED2D00721644 /* h4.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB2A1AD3ED2D00721644 /* h4.png */; }; 31 | FBA6AB601AD3ED2D00721644 /* h4@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB2B1AD3ED2D00721644 /* h4@2x.png */; }; 32 | FBA6AB611AD3ED2D00721644 /* h5.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB2C1AD3ED2D00721644 /* h5.png */; }; 33 | FBA6AB621AD3ED2D00721644 /* h5@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB2D1AD3ED2D00721644 /* h5@2x.png */; }; 34 | FBA6AB631AD3ED2D00721644 /* h6.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB2E1AD3ED2D00721644 /* h6.png */; }; 35 | FBA6AB641AD3ED2D00721644 /* h6@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB2F1AD3ED2D00721644 /* h6@2x.png */; }; 36 | FBA6AB651AD3ED2D00721644 /* indent.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB301AD3ED2D00721644 /* indent.png */; }; 37 | FBA6AB661AD3ED2D00721644 /* indent@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB311AD3ED2D00721644 /* indent@2x.png */; }; 38 | FBA6AB671AD3ED2D00721644 /* insert_image.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB321AD3ED2D00721644 /* insert_image.png */; }; 39 | FBA6AB681AD3ED2D00721644 /* insert_image@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB331AD3ED2D00721644 /* insert_image@2x.png */; }; 40 | FBA6AB691AD3ED2D00721644 /* insert_link.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB341AD3ED2D00721644 /* insert_link.png */; }; 41 | FBA6AB6A1AD3ED2D00721644 /* insert_link@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB351AD3ED2D00721644 /* insert_link@2x.png */; }; 42 | FBA6AB6B1AD3ED2D00721644 /* italic.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB361AD3ED2D00721644 /* italic.png */; }; 43 | FBA6AB6C1AD3ED2D00721644 /* italic@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB371AD3ED2D00721644 /* italic@2x.png */; }; 44 | FBA6AB6D1AD3ED2D00721644 /* justify_center.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB381AD3ED2D00721644 /* justify_center.png */; }; 45 | FBA6AB6E1AD3ED2D00721644 /* justify_center@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB391AD3ED2D00721644 /* justify_center@2x.png */; }; 46 | FBA6AB6F1AD3ED2D00721644 /* justify_left.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB3A1AD3ED2D00721644 /* justify_left.png */; }; 47 | FBA6AB701AD3ED2D00721644 /* justify_left@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB3B1AD3ED2D00721644 /* justify_left@2x.png */; }; 48 | FBA6AB711AD3ED2D00721644 /* justify_right.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB3C1AD3ED2D00721644 /* justify_right.png */; }; 49 | FBA6AB721AD3ED2D00721644 /* justify_right@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB3D1AD3ED2D00721644 /* justify_right@2x.png */; }; 50 | FBA6AB731AD3ED2D00721644 /* outdent.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB3E1AD3ED2D00721644 /* outdent.png */; }; 51 | FBA6AB741AD3ED2D00721644 /* outdent@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB3F1AD3ED2D00721644 /* outdent@2x.png */; }; 52 | FBA6AB751AD3ED2D00721644 /* redo.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB401AD3ED2D00721644 /* redo.png */; }; 53 | FBA6AB761AD3ED2D00721644 /* redo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB411AD3ED2D00721644 /* redo@2x.png */; }; 54 | FBA6AB771AD3ED2D00721644 /* strikethrough.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB421AD3ED2D00721644 /* strikethrough.png */; }; 55 | FBA6AB781AD3ED2D00721644 /* strikethrough@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB431AD3ED2D00721644 /* strikethrough@2x.png */; }; 56 | FBA6AB791AD3ED2D00721644 /* subscript.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB441AD3ED2D00721644 /* subscript.png */; }; 57 | FBA6AB7A1AD3ED2D00721644 /* subscript@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB451AD3ED2D00721644 /* subscript@2x.png */; }; 58 | FBA6AB7B1AD3ED2D00721644 /* superscript.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB461AD3ED2D00721644 /* superscript.png */; }; 59 | FBA6AB7C1AD3ED2D00721644 /* superscript@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB471AD3ED2D00721644 /* superscript@2x.png */; }; 60 | FBA6AB7D1AD3ED2D00721644 /* text_color.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB481AD3ED2D00721644 /* text_color.png */; }; 61 | FBA6AB7E1AD3ED2D00721644 /* text_color@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB491AD3ED2D00721644 /* text_color@2x.png */; }; 62 | FBA6AB7F1AD3ED2D00721644 /* underline.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB4A1AD3ED2D00721644 /* underline.png */; }; 63 | FBA6AB801AD3ED2D00721644 /* underline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB4B1AD3ED2D00721644 /* underline@2x.png */; }; 64 | FBA6AB811AD3ED2D00721644 /* undo.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB4C1AD3ED2D00721644 /* undo.png */; }; 65 | FBA6AB821AD3ED2D00721644 /* undo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FBA6AB4D1AD3ED2D00721644 /* undo@2x.png */; }; 66 | FBA6AB881AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.h in Headers */ = {isa = PBXBuildFile; fileRef = FBA6AB831AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.h */; settings = {ATTRIBUTES = (Public, ); }; }; 67 | FBA6AB891AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.m in Sources */ = {isa = PBXBuildFile; fileRef = FBA6AB841AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.m */; }; 68 | FBA6AB8A1AD3ED3C00721644 /* RichEditorOptionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBA6AB851AD3ED3C00721644 /* RichEditorOptionItem.swift */; }; 69 | FBA6AB8B1AD3ED3C00721644 /* RichEditorToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBA6AB861AD3ED3C00721644 /* RichEditorToolbar.swift */; }; 70 | FBA6AB8C1AD3ED3C00721644 /* RichEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBA6AB871AD3ED3C00721644 /* RichEditorView.swift */; }; 71 | FBA6ABC51AD3FD2E00721644 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBA6ABC41AD3FD2E00721644 /* UIKit.framework */; }; 72 | /* End PBXBuildFile section */ 73 | 74 | /* Begin PBXContainerItemProxy section */ 75 | FBA6AB061AD3EC9F00721644 /* PBXContainerItemProxy */ = { 76 | isa = PBXContainerItemProxy; 77 | containerPortal = FBA6AAF01AD3EC9F00721644 /* Project object */; 78 | proxyType = 1; 79 | remoteGlobalIDString = FBA6AAF81AD3EC9F00721644; 80 | remoteInfo = RichEditorView; 81 | }; 82 | /* End PBXContainerItemProxy section */ 83 | 84 | /* Begin PBXFileReference section */ 85 | 947A71A01C0F9DED00BDF9FC /* UIView+Responder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Responder.swift"; path = "Classes/UIView+Responder.swift"; sourceTree = " "; }; 86 | FBA6AAF91AD3EC9F00721644 /* RichEditorView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RichEditorView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 87 | FBA6AAFD1AD3EC9F00721644 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = " "; }; 88 | FBA6AAFE1AD3EC9F00721644 /* RichEditorView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RichEditorView.h; sourceTree = " "; }; 89 | FBA6AB041AD3EC9F00721644 /* RichEditorViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RichEditorViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 90 | FBA6AB0A1AD3EC9F00721644 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = " "; }; 91 | FBA6AB0B1AD3EC9F00721644 /* RichEditorViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RichEditorViewTests.swift; sourceTree = " "; }; 92 | FBA6AB181AD3ED2D00721644 /* checking.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = checking.js; sourceTree = " "; }; 93 | FBA6AB191AD3ED2D00721644 /* normalize.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = normalize.css; sourceTree = " "; }; 94 | FBA6AB1A1AD3ED2D00721644 /* rich_editor.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = rich_editor.html; sourceTree = " "; }; 95 | FBA6AB1B1AD3ED2D00721644 /* rich_editor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = rich_editor.js; sourceTree = " "; }; 96 | FBA6AB1C1AD3ED2D00721644 /* style.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = style.css; sourceTree = " "; }; 97 | FBA6AB1E1AD3ED2D00721644 /* bg_color.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bg_color.png; sourceTree = " "; }; 98 | FBA6AB1F1AD3ED2D00721644 /* bg_color@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bg_color@2x.png"; sourceTree = " "; }; 99 | FBA6AB201AD3ED2D00721644 /* bold.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bold.png; sourceTree = " "; }; 100 | FBA6AB211AD3ED2D00721644 /* bold@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bold@2x.png"; sourceTree = " "; }; 101 | FBA6AB221AD3ED2D00721644 /* clear.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = clear.png; sourceTree = " "; }; 102 | FBA6AB231AD3ED2D00721644 /* clear@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "clear@2x.png"; sourceTree = " "; }; 103 | FBA6AB241AD3ED2D00721644 /* h1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h1.png; sourceTree = " "; }; 104 | FBA6AB251AD3ED2D00721644 /* h1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "h1@2x.png"; sourceTree = " "; }; 105 | FBA6AB261AD3ED2D00721644 /* h2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h2.png; sourceTree = " "; }; 106 | FBA6AB271AD3ED2D00721644 /* h2@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "h2@2x.png"; sourceTree = " "; }; 107 | FBA6AB281AD3ED2D00721644 /* h3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h3.png; sourceTree = " "; }; 108 | FBA6AB291AD3ED2D00721644 /* h3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "h3@2x.png"; sourceTree = " "; }; 109 | FBA6AB2A1AD3ED2D00721644 /* h4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h4.png; sourceTree = " "; }; 110 | FBA6AB2B1AD3ED2D00721644 /* h4@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "h4@2x.png"; sourceTree = " "; }; 111 | FBA6AB2C1AD3ED2D00721644 /* h5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h5.png; sourceTree = " "; }; 112 | FBA6AB2D1AD3ED2D00721644 /* h5@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "h5@2x.png"; sourceTree = " "; }; 113 | FBA6AB2E1AD3ED2D00721644 /* h6.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h6.png; sourceTree = " "; }; 114 | FBA6AB2F1AD3ED2D00721644 /* h6@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "h6@2x.png"; sourceTree = " "; }; 115 | FBA6AB301AD3ED2D00721644 /* indent.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = indent.png; sourceTree = " "; }; 116 | FBA6AB311AD3ED2D00721644 /* indent@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "indent@2x.png"; sourceTree = " "; }; 117 | FBA6AB321AD3ED2D00721644 /* insert_image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = insert_image.png; sourceTree = " "; }; 118 | FBA6AB331AD3ED2D00721644 /* insert_image@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "insert_image@2x.png"; sourceTree = " "; }; 119 | FBA6AB341AD3ED2D00721644 /* insert_link.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = insert_link.png; sourceTree = " "; }; 120 | FBA6AB351AD3ED2D00721644 /* insert_link@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "insert_link@2x.png"; sourceTree = " "; }; 121 | FBA6AB361AD3ED2D00721644 /* italic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = italic.png; sourceTree = " "; }; 122 | FBA6AB371AD3ED2D00721644 /* italic@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "italic@2x.png"; sourceTree = " "; }; 123 | FBA6AB381AD3ED2D00721644 /* justify_center.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = justify_center.png; sourceTree = " "; }; 124 | FBA6AB391AD3ED2D00721644 /* justify_center@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "justify_center@2x.png"; sourceTree = " "; }; 125 | FBA6AB3A1AD3ED2D00721644 /* justify_left.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = justify_left.png; sourceTree = " "; }; 126 | FBA6AB3B1AD3ED2D00721644 /* justify_left@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "justify_left@2x.png"; sourceTree = " "; }; 127 | FBA6AB3C1AD3ED2D00721644 /* justify_right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = justify_right.png; sourceTree = " "; }; 128 | FBA6AB3D1AD3ED2D00721644 /* justify_right@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "justify_right@2x.png"; sourceTree = " "; }; 129 | FBA6AB3E1AD3ED2D00721644 /* outdent.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = outdent.png; sourceTree = " "; }; 130 | FBA6AB3F1AD3ED2D00721644 /* outdent@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "outdent@2x.png"; sourceTree = " "; }; 131 | FBA6AB401AD3ED2D00721644 /* redo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = redo.png; sourceTree = " "; }; 132 | FBA6AB411AD3ED2D00721644 /* redo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "redo@2x.png"; sourceTree = " "; }; 133 | FBA6AB421AD3ED2D00721644 /* strikethrough.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = strikethrough.png; sourceTree = " "; }; 134 | FBA6AB431AD3ED2D00721644 /* strikethrough@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "strikethrough@2x.png"; sourceTree = " "; }; 135 | FBA6AB441AD3ED2D00721644 /* subscript.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = subscript.png; sourceTree = " "; }; 136 | FBA6AB451AD3ED2D00721644 /* subscript@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "subscript@2x.png"; sourceTree = " "; }; 137 | FBA6AB461AD3ED2D00721644 /* superscript.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = superscript.png; sourceTree = " "; }; 138 | FBA6AB471AD3ED2D00721644 /* superscript@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "superscript@2x.png"; sourceTree = " "; }; 139 | FBA6AB481AD3ED2D00721644 /* text_color.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = text_color.png; sourceTree = " "; }; 140 | FBA6AB491AD3ED2D00721644 /* text_color@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "text_color@2x.png"; sourceTree = " "; }; 141 | FBA6AB4A1AD3ED2D00721644 /* underline.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = underline.png; sourceTree = " "; }; 142 | FBA6AB4B1AD3ED2D00721644 /* underline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "underline@2x.png"; sourceTree = " "; }; 143 | FBA6AB4C1AD3ED2D00721644 /* undo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = undo.png; sourceTree = " "; }; 144 | FBA6AB4D1AD3ED2D00721644 /* undo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "undo@2x.png"; sourceTree = " "; }; 145 | FBA6AB831AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "CJWWebView+HackishAccessoryHiding.h"; path = "Classes/CJWWebView+HackishAccessoryHiding.h"; sourceTree = " "; }; 146 | FBA6AB841AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "CJWWebView+HackishAccessoryHiding.m"; path = "Classes/CJWWebView+HackishAccessoryHiding.m"; sourceTree = " "; }; 147 | FBA6AB851AD3ED3C00721644 /* RichEditorOptionItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RichEditorOptionItem.swift; path = Classes/RichEditorOptionItem.swift; sourceTree = " "; }; 148 | FBA6AB861AD3ED3C00721644 /* RichEditorToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RichEditorToolbar.swift; path = Classes/RichEditorToolbar.swift; sourceTree = " "; }; 149 | FBA6AB871AD3ED3C00721644 /* RichEditorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RichEditorView.swift; path = Classes/RichEditorView.swift; sourceTree = " "; }; 150 | FBA6AB951AD3F3E700721644 /* RichEditorView-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RichEditorView-Bridging-Header.h"; sourceTree = " "; }; 151 | FBA6ABC41AD3FD2E00721644 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 152 | /* End PBXFileReference section */ 153 | 154 | /* Begin PBXFrameworksBuildPhase section */ 155 | FBA6AAF51AD3EC9F00721644 /* Frameworks */ = { 156 | isa = PBXFrameworksBuildPhase; 157 | buildActionMask = 2147483647; 158 | files = ( 159 | FBA6ABC51AD3FD2E00721644 /* UIKit.framework in Frameworks */, 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | }; 163 | FBA6AB011AD3EC9F00721644 /* Frameworks */ = { 164 | isa = PBXFrameworksBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | FBA6AB051AD3EC9F00721644 /* RichEditorView.framework in Frameworks */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXFrameworksBuildPhase section */ 172 | 173 | /* Begin PBXGroup section */ 174 | FBA6AAEF1AD3EC9F00721644 = { 175 | isa = PBXGroup; 176 | children = ( 177 | FBA6ABC41AD3FD2E00721644 /* UIKit.framework */, 178 | FBA6AAFB1AD3EC9F00721644 /* RichEditorView */, 179 | FBA6AB081AD3EC9F00721644 /* RichEditorViewTests */, 180 | FBA6AAFA1AD3EC9F00721644 /* Products */, 181 | ); 182 | sourceTree = " "; 183 | }; 184 | FBA6AAFA1AD3EC9F00721644 /* Products */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | FBA6AAF91AD3EC9F00721644 /* RichEditorView.framework */, 188 | FBA6AB041AD3EC9F00721644 /* RichEditorViewTests.xctest */, 189 | ); 190 | name = Products; 191 | sourceTree = " "; 192 | }; 193 | FBA6AAFB1AD3EC9F00721644 /* RichEditorView */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | FBA6AB161AD3ED1B00721644 /* Assets */, 197 | FBA6AB151AD3ED1700721644 /* Classes */, 198 | FBA6AAFE1AD3EC9F00721644 /* RichEditorView.h */, 199 | FBA6AAFC1AD3EC9F00721644 /* Supporting Files */, 200 | ); 201 | path = RichEditorView; 202 | sourceTree = " "; 203 | }; 204 | FBA6AAFC1AD3EC9F00721644 /* Supporting Files */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | FBA6AAFD1AD3EC9F00721644 /* Info.plist */, 208 | FBA6AB951AD3F3E700721644 /* RichEditorView-Bridging-Header.h */, 209 | ); 210 | name = "Supporting Files"; 211 | sourceTree = " "; 212 | }; 213 | FBA6AB081AD3EC9F00721644 /* RichEditorViewTests */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | FBA6AB0B1AD3EC9F00721644 /* RichEditorViewTests.swift */, 217 | FBA6AB091AD3EC9F00721644 /* Supporting Files */, 218 | ); 219 | path = RichEditorViewTests; 220 | sourceTree = " "; 221 | }; 222 | FBA6AB091AD3EC9F00721644 /* Supporting Files */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | FBA6AB0A1AD3EC9F00721644 /* Info.plist */, 226 | ); 227 | name = "Supporting Files"; 228 | sourceTree = " "; 229 | }; 230 | FBA6AB151AD3ED1700721644 /* Classes */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | FBA6AB831AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.h */, 234 | FBA6AB841AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.m */, 235 | FBA6AB851AD3ED3C00721644 /* RichEditorOptionItem.swift */, 236 | FBA6AB861AD3ED3C00721644 /* RichEditorToolbar.swift */, 237 | FBA6AB871AD3ED3C00721644 /* RichEditorView.swift */, 238 | 947A71A01C0F9DED00BDF9FC /* UIView+Responder.swift */, 239 | ); 240 | name = Classes; 241 | sourceTree = " "; 242 | }; 243 | FBA6AB161AD3ED1B00721644 /* Assets */ = { 244 | isa = PBXGroup; 245 | children = ( 246 | FBA6AB171AD3ED2D00721644 /* editor */, 247 | FBA6AB1D1AD3ED2D00721644 /* icons */, 248 | ); 249 | name = Assets; 250 | sourceTree = " "; 251 | }; 252 | FBA6AB171AD3ED2D00721644 /* editor */ = { 253 | isa = PBXGroup; 254 | children = ( 255 | FBA6AB181AD3ED2D00721644 /* checking.js */, 256 | FBA6AB191AD3ED2D00721644 /* normalize.css */, 257 | FBA6AB1A1AD3ED2D00721644 /* rich_editor.html */, 258 | FBA6AB1B1AD3ED2D00721644 /* rich_editor.js */, 259 | FBA6AB1C1AD3ED2D00721644 /* style.css */, 260 | ); 261 | name = editor; 262 | path = Assets/editor; 263 | sourceTree = " "; 264 | }; 265 | FBA6AB1D1AD3ED2D00721644 /* icons */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | FBA6AB1E1AD3ED2D00721644 /* bg_color.png */, 269 | FBA6AB1F1AD3ED2D00721644 /* bg_color@2x.png */, 270 | FBA6AB201AD3ED2D00721644 /* bold.png */, 271 | FBA6AB211AD3ED2D00721644 /* bold@2x.png */, 272 | FBA6AB221AD3ED2D00721644 /* clear.png */, 273 | FBA6AB231AD3ED2D00721644 /* clear@2x.png */, 274 | FBA6AB241AD3ED2D00721644 /* h1.png */, 275 | FBA6AB251AD3ED2D00721644 /* h1@2x.png */, 276 | FBA6AB261AD3ED2D00721644 /* h2.png */, 277 | FBA6AB271AD3ED2D00721644 /* h2@2x.png */, 278 | FBA6AB281AD3ED2D00721644 /* h3.png */, 279 | FBA6AB291AD3ED2D00721644 /* h3@2x.png */, 280 | FBA6AB2A1AD3ED2D00721644 /* h4.png */, 281 | FBA6AB2B1AD3ED2D00721644 /* h4@2x.png */, 282 | FBA6AB2C1AD3ED2D00721644 /* h5.png */, 283 | FBA6AB2D1AD3ED2D00721644 /* h5@2x.png */, 284 | FBA6AB2E1AD3ED2D00721644 /* h6.png */, 285 | FBA6AB2F1AD3ED2D00721644 /* h6@2x.png */, 286 | FBA6AB301AD3ED2D00721644 /* indent.png */, 287 | FBA6AB311AD3ED2D00721644 /* indent@2x.png */, 288 | FBA6AB321AD3ED2D00721644 /* insert_image.png */, 289 | FBA6AB331AD3ED2D00721644 /* insert_image@2x.png */, 290 | FBA6AB341AD3ED2D00721644 /* insert_link.png */, 291 | FBA6AB351AD3ED2D00721644 /* insert_link@2x.png */, 292 | FBA6AB361AD3ED2D00721644 /* italic.png */, 293 | FBA6AB371AD3ED2D00721644 /* italic@2x.png */, 294 | FBA6AB381AD3ED2D00721644 /* justify_center.png */, 295 | FBA6AB391AD3ED2D00721644 /* justify_center@2x.png */, 296 | FBA6AB3A1AD3ED2D00721644 /* justify_left.png */, 297 | FBA6AB3B1AD3ED2D00721644 /* justify_left@2x.png */, 298 | FBA6AB3C1AD3ED2D00721644 /* justify_right.png */, 299 | FBA6AB3D1AD3ED2D00721644 /* justify_right@2x.png */, 300 | FBA6AB3E1AD3ED2D00721644 /* outdent.png */, 301 | FBA6AB3F1AD3ED2D00721644 /* outdent@2x.png */, 302 | FBA6AB401AD3ED2D00721644 /* redo.png */, 303 | FBA6AB411AD3ED2D00721644 /* redo@2x.png */, 304 | FBA6AB421AD3ED2D00721644 /* strikethrough.png */, 305 | FBA6AB431AD3ED2D00721644 /* strikethrough@2x.png */, 306 | FBA6AB441AD3ED2D00721644 /* subscript.png */, 307 | FBA6AB451AD3ED2D00721644 /* subscript@2x.png */, 308 | FBA6AB461AD3ED2D00721644 /* superscript.png */, 309 | FBA6AB471AD3ED2D00721644 /* superscript@2x.png */, 310 | FBA6AB481AD3ED2D00721644 /* text_color.png */, 311 | FBA6AB491AD3ED2D00721644 /* text_color@2x.png */, 312 | FBA6AB4A1AD3ED2D00721644 /* underline.png */, 313 | FBA6AB4B1AD3ED2D00721644 /* underline@2x.png */, 314 | FBA6AB4C1AD3ED2D00721644 /* undo.png */, 315 | FBA6AB4D1AD3ED2D00721644 /* undo@2x.png */, 316 | ); 317 | name = icons; 318 | path = Assets/icons; 319 | sourceTree = " "; 320 | }; 321 | /* End PBXGroup section */ 322 | 323 | /* Begin PBXHeadersBuildPhase section */ 324 | FBA6AAF61AD3EC9F00721644 /* Headers */ = { 325 | isa = PBXHeadersBuildPhase; 326 | buildActionMask = 2147483647; 327 | files = ( 328 | FBA6AAFF1AD3EC9F00721644 /* RichEditorView.h in Headers */, 329 | FBA6AB881AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.h in Headers */, 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | /* End PBXHeadersBuildPhase section */ 334 | 335 | /* Begin PBXNativeTarget section */ 336 | FBA6AAF81AD3EC9F00721644 /* RichEditorView */ = { 337 | isa = PBXNativeTarget; 338 | buildConfigurationList = FBA6AB0F1AD3EC9F00721644 /* Build configuration list for PBXNativeTarget "RichEditorView" */; 339 | buildPhases = ( 340 | FBA6AAF41AD3EC9F00721644 /* Sources */, 341 | FBA6AAF51AD3EC9F00721644 /* Frameworks */, 342 | FBA6AAF61AD3EC9F00721644 /* Headers */, 343 | FBA6AAF71AD3EC9F00721644 /* Resources */, 344 | ); 345 | buildRules = ( 346 | ); 347 | dependencies = ( 348 | ); 349 | name = RichEditorView; 350 | productName = RichEditorView; 351 | productReference = FBA6AAF91AD3EC9F00721644 /* RichEditorView.framework */; 352 | productType = "com.apple.product-type.framework"; 353 | }; 354 | FBA6AB031AD3EC9F00721644 /* RichEditorViewTests */ = { 355 | isa = PBXNativeTarget; 356 | buildConfigurationList = FBA6AB121AD3EC9F00721644 /* Build configuration list for PBXNativeTarget "RichEditorViewTests" */; 357 | buildPhases = ( 358 | FBA6AB001AD3EC9F00721644 /* Sources */, 359 | FBA6AB011AD3EC9F00721644 /* Frameworks */, 360 | FBA6AB021AD3EC9F00721644 /* Resources */, 361 | ); 362 | buildRules = ( 363 | ); 364 | dependencies = ( 365 | FBA6AB071AD3EC9F00721644 /* PBXTargetDependency */, 366 | ); 367 | name = RichEditorViewTests; 368 | productName = RichEditorViewTests; 369 | productReference = FBA6AB041AD3EC9F00721644 /* RichEditorViewTests.xctest */; 370 | productType = "com.apple.product-type.bundle.unit-test"; 371 | }; 372 | /* End PBXNativeTarget section */ 373 | 374 | /* Begin PBXProject section */ 375 | FBA6AAF01AD3EC9F00721644 /* Project object */ = { 376 | isa = PBXProject; 377 | attributes = { 378 | LastSwiftUpdateCheck = 0710; 379 | LastUpgradeCheck = 0820; 380 | TargetAttributes = { 381 | FBA6AAF81AD3EC9F00721644 = { 382 | CreatedOnToolsVersion = 6.2; 383 | LastSwiftMigration = 0820; 384 | }; 385 | FBA6AB031AD3EC9F00721644 = { 386 | CreatedOnToolsVersion = 6.2; 387 | LastSwiftMigration = 0820; 388 | }; 389 | }; 390 | }; 391 | buildConfigurationList = FBA6AAF31AD3EC9F00721644 /* Build configuration list for PBXProject "RichEditorView" */; 392 | compatibilityVersion = "Xcode 3.2"; 393 | developmentRegion = English; 394 | hasScannedForEncodings = 0; 395 | knownRegions = ( 396 | en, 397 | ); 398 | mainGroup = FBA6AAEF1AD3EC9F00721644; 399 | productRefGroup = FBA6AAFA1AD3EC9F00721644 /* Products */; 400 | projectDirPath = ""; 401 | projectRoot = ""; 402 | targets = ( 403 | FBA6AAF81AD3EC9F00721644 /* RichEditorView */, 404 | FBA6AB031AD3EC9F00721644 /* RichEditorViewTests */, 405 | ); 406 | }; 407 | /* End PBXProject section */ 408 | 409 | /* Begin PBXResourcesBuildPhase section */ 410 | FBA6AAF71AD3EC9F00721644 /* Resources */ = { 411 | isa = PBXResourcesBuildPhase; 412 | buildActionMask = 2147483647; 413 | files = ( 414 | FBA6AB641AD3ED2D00721644 /* h6@2x.png in Resources */, 415 | FBA6AB541AD3ED2D00721644 /* bg_color@2x.png in Resources */, 416 | FBA6AB731AD3ED2D00721644 /* outdent.png in Resources */, 417 | FBA6AB591AD3ED2D00721644 /* h1.png in Resources */, 418 | FBA6AB691AD3ED2D00721644 /* insert_link.png in Resources */, 419 | FBA6AB5E1AD3ED2D00721644 /* h3@2x.png in Resources */, 420 | FBA6AB781AD3ED2D00721644 /* strikethrough@2x.png in Resources */, 421 | FBA6AB661AD3ED2D00721644 /* indent@2x.png in Resources */, 422 | FBA6AB821AD3ED2D00721644 /* undo@2x.png in Resources */, 423 | FBA6AB5B1AD3ED2D00721644 /* h2.png in Resources */, 424 | FBA6AB7A1AD3ED2D00721644 /* subscript@2x.png in Resources */, 425 | FBA6AB5F1AD3ED2D00721644 /* h4.png in Resources */, 426 | FBA6AB681AD3ED2D00721644 /* insert_image@2x.png in Resources */, 427 | FBA6AB651AD3ED2D00721644 /* indent.png in Resources */, 428 | FBA6AB5D1AD3ED2D00721644 /* h3.png in Resources */, 429 | FBA6AB631AD3ED2D00721644 /* h6.png in Resources */, 430 | FBA6AB561AD3ED2D00721644 /* bold@2x.png in Resources */, 431 | FBA6AB6E1AD3ED2D00721644 /* justify_center@2x.png in Resources */, 432 | FBA6AB5A1AD3ED2D00721644 /* h1@2x.png in Resources */, 433 | FBA6AB721AD3ED2D00721644 /* justify_right@2x.png in Resources */, 434 | FBA6AB7D1AD3ED2D00721644 /* text_color.png in Resources */, 435 | FBA6AB621AD3ED2D00721644 /* h5@2x.png in Resources */, 436 | FBA6AB5C1AD3ED2D00721644 /* h2@2x.png in Resources */, 437 | FBA6AB6B1AD3ED2D00721644 /* italic.png in Resources */, 438 | FBA6AB771AD3ED2D00721644 /* strikethrough.png in Resources */, 439 | FBA6AB751AD3ED2D00721644 /* redo.png in Resources */, 440 | FBA6AB7F1AD3ED2D00721644 /* underline.png in Resources */, 441 | FBA6AB6A1AD3ED2D00721644 /* insert_link@2x.png in Resources */, 442 | FBA6AB761AD3ED2D00721644 /* redo@2x.png in Resources */, 443 | FBA6AB6D1AD3ED2D00721644 /* justify_center.png in Resources */, 444 | FBA6AB701AD3ED2D00721644 /* justify_left@2x.png in Resources */, 445 | FBA6AB611AD3ED2D00721644 /* h5.png in Resources */, 446 | FBA6AB7E1AD3ED2D00721644 /* text_color@2x.png in Resources */, 447 | FBA6AB811AD3ED2D00721644 /* undo.png in Resources */, 448 | FBA6AB511AD3ED2D00721644 /* rich_editor.js in Resources */, 449 | FBA6AB521AD3ED2D00721644 /* style.css in Resources */, 450 | FBA6AB601AD3ED2D00721644 /* h4@2x.png in Resources */, 451 | FBA6AB581AD3ED2D00721644 /* clear@2x.png in Resources */, 452 | FBA6AB801AD3ED2D00721644 /* underline@2x.png in Resources */, 453 | FBA6AB711AD3ED2D00721644 /* justify_right.png in Resources */, 454 | FBA6AB7C1AD3ED2D00721644 /* superscript@2x.png in Resources */, 455 | FBA6AB551AD3ED2D00721644 /* bold.png in Resources */, 456 | FBA6AB6F1AD3ED2D00721644 /* justify_left.png in Resources */, 457 | FBA6AB4F1AD3ED2D00721644 /* normalize.css in Resources */, 458 | FBA6AB571AD3ED2D00721644 /* clear.png in Resources */, 459 | FBA6AB741AD3ED2D00721644 /* outdent@2x.png in Resources */, 460 | FBA6AB7B1AD3ED2D00721644 /* superscript.png in Resources */, 461 | FBA6AB791AD3ED2D00721644 /* subscript.png in Resources */, 462 | FBA6AB531AD3ED2D00721644 /* bg_color.png in Resources */, 463 | FBA6AB671AD3ED2D00721644 /* insert_image.png in Resources */, 464 | FBA6AB501AD3ED2D00721644 /* rich_editor.html in Resources */, 465 | FBA6AB6C1AD3ED2D00721644 /* italic@2x.png in Resources */, 466 | ); 467 | runOnlyForDeploymentPostprocessing = 0; 468 | }; 469 | FBA6AB021AD3EC9F00721644 /* Resources */ = { 470 | isa = PBXResourcesBuildPhase; 471 | buildActionMask = 2147483647; 472 | files = ( 473 | ); 474 | runOnlyForDeploymentPostprocessing = 0; 475 | }; 476 | /* End PBXResourcesBuildPhase section */ 477 | 478 | /* Begin PBXSourcesBuildPhase section */ 479 | FBA6AAF41AD3EC9F00721644 /* Sources */ = { 480 | isa = PBXSourcesBuildPhase; 481 | buildActionMask = 2147483647; 482 | files = ( 483 | FBA6AB8A1AD3ED3C00721644 /* RichEditorOptionItem.swift in Sources */, 484 | FBA6AB8B1AD3ED3C00721644 /* RichEditorToolbar.swift in Sources */, 485 | FBA6AB891AD3ED3C00721644 /* CJWWebView+HackishAccessoryHiding.m in Sources */, 486 | FBA6AB8C1AD3ED3C00721644 /* RichEditorView.swift in Sources */, 487 | 947A71A11C0F9DED00BDF9FC /* UIView+Responder.swift in Sources */, 488 | ); 489 | runOnlyForDeploymentPostprocessing = 0; 490 | }; 491 | FBA6AB001AD3EC9F00721644 /* Sources */ = { 492 | isa = PBXSourcesBuildPhase; 493 | buildActionMask = 2147483647; 494 | files = ( 495 | FBA6AB0C1AD3EC9F00721644 /* RichEditorViewTests.swift in Sources */, 496 | ); 497 | runOnlyForDeploymentPostprocessing = 0; 498 | }; 499 | /* End PBXSourcesBuildPhase section */ 500 | 501 | /* Begin PBXTargetDependency section */ 502 | FBA6AB071AD3EC9F00721644 /* PBXTargetDependency */ = { 503 | isa = PBXTargetDependency; 504 | target = FBA6AAF81AD3EC9F00721644 /* RichEditorView */; 505 | targetProxy = FBA6AB061AD3EC9F00721644 /* PBXContainerItemProxy */; 506 | }; 507 | /* End PBXTargetDependency section */ 508 | 509 | /* Begin XCBuildConfiguration section */ 510 | FBA6AB0D1AD3EC9F00721644 /* Debug */ = { 511 | isa = XCBuildConfiguration; 512 | buildSettings = { 513 | ALWAYS_SEARCH_USER_PATHS = NO; 514 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 515 | CLANG_CXX_LIBRARY = "libc++"; 516 | CLANG_ENABLE_MODULES = YES; 517 | CLANG_ENABLE_OBJC_ARC = YES; 518 | CLANG_WARN_BOOL_CONVERSION = YES; 519 | CLANG_WARN_CONSTANT_CONVERSION = YES; 520 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 521 | CLANG_WARN_EMPTY_BODY = YES; 522 | CLANG_WARN_ENUM_CONVERSION = YES; 523 | CLANG_WARN_INFINITE_RECURSION = YES; 524 | CLANG_WARN_INT_CONVERSION = YES; 525 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 526 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 527 | CLANG_WARN_UNREACHABLE_CODE = YES; 528 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 529 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 530 | COPY_PHASE_STRIP = NO; 531 | CURRENT_PROJECT_VERSION = 1; 532 | ENABLE_STRICT_OBJC_MSGSEND = YES; 533 | ENABLE_TESTABILITY = YES; 534 | GCC_C_LANGUAGE_STANDARD = gnu99; 535 | GCC_DYNAMIC_NO_PIC = NO; 536 | GCC_NO_COMMON_BLOCKS = YES; 537 | GCC_OPTIMIZATION_LEVEL = 0; 538 | GCC_PREPROCESSOR_DEFINITIONS = ( 539 | "DEBUG=1", 540 | "$(inherited)", 541 | ); 542 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 543 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 544 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 545 | GCC_WARN_UNDECLARED_SELECTOR = YES; 546 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 547 | GCC_WARN_UNUSED_FUNCTION = YES; 548 | GCC_WARN_UNUSED_VARIABLE = YES; 549 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 550 | MTL_ENABLE_DEBUG_INFO = YES; 551 | ONLY_ACTIVE_ARCH = YES; 552 | SDKROOT = iphoneos; 553 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 554 | TARGETED_DEVICE_FAMILY = "1,2"; 555 | VERSIONING_SYSTEM = "apple-generic"; 556 | VERSION_INFO_PREFIX = ""; 557 | }; 558 | name = Debug; 559 | }; 560 | FBA6AB0E1AD3EC9F00721644 /* Release */ = { 561 | isa = XCBuildConfiguration; 562 | buildSettings = { 563 | ALWAYS_SEARCH_USER_PATHS = NO; 564 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 565 | CLANG_CXX_LIBRARY = "libc++"; 566 | CLANG_ENABLE_MODULES = YES; 567 | CLANG_ENABLE_OBJC_ARC = YES; 568 | CLANG_WARN_BOOL_CONVERSION = YES; 569 | CLANG_WARN_CONSTANT_CONVERSION = YES; 570 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 571 | CLANG_WARN_EMPTY_BODY = YES; 572 | CLANG_WARN_ENUM_CONVERSION = YES; 573 | CLANG_WARN_INFINITE_RECURSION = YES; 574 | CLANG_WARN_INT_CONVERSION = YES; 575 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 576 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 577 | CLANG_WARN_UNREACHABLE_CODE = YES; 578 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 579 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 580 | COPY_PHASE_STRIP = YES; 581 | CURRENT_PROJECT_VERSION = 1; 582 | ENABLE_NS_ASSERTIONS = NO; 583 | ENABLE_STRICT_OBJC_MSGSEND = YES; 584 | GCC_C_LANGUAGE_STANDARD = gnu99; 585 | GCC_NO_COMMON_BLOCKS = YES; 586 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 587 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 588 | GCC_WARN_UNDECLARED_SELECTOR = YES; 589 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 590 | GCC_WARN_UNUSED_FUNCTION = YES; 591 | GCC_WARN_UNUSED_VARIABLE = YES; 592 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 593 | MTL_ENABLE_DEBUG_INFO = NO; 594 | SDKROOT = iphoneos; 595 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 596 | TARGETED_DEVICE_FAMILY = "1,2"; 597 | VALIDATE_PRODUCT = YES; 598 | VERSIONING_SYSTEM = "apple-generic"; 599 | VERSION_INFO_PREFIX = ""; 600 | }; 601 | name = Release; 602 | }; 603 | FBA6AB101AD3EC9F00721644 /* Debug */ = { 604 | isa = XCBuildConfiguration; 605 | buildSettings = { 606 | CLANG_ENABLE_MODULES = YES; 607 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 608 | DEFINES_MODULE = YES; 609 | DYLIB_COMPATIBILITY_VERSION = 1; 610 | DYLIB_CURRENT_VERSION = 1; 611 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 612 | INFOPLIST_FILE = RichEditorView/Info.plist; 613 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 614 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 615 | PRODUCT_BUNDLE_IDENTIFIER = "com.cjwirth.$(PRODUCT_NAME:rfc1034identifier)"; 616 | PRODUCT_NAME = "$(TARGET_NAME)"; 617 | SKIP_INSTALL = YES; 618 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 619 | SWIFT_VERSION = 3.0; 620 | }; 621 | name = Debug; 622 | }; 623 | FBA6AB111AD3EC9F00721644 /* Release */ = { 624 | isa = XCBuildConfiguration; 625 | buildSettings = { 626 | CLANG_ENABLE_MODULES = YES; 627 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 628 | DEFINES_MODULE = YES; 629 | DYLIB_COMPATIBILITY_VERSION = 1; 630 | DYLIB_CURRENT_VERSION = 1; 631 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 632 | INFOPLIST_FILE = RichEditorView/Info.plist; 633 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 634 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 635 | PRODUCT_BUNDLE_IDENTIFIER = "com.cjwirth.$(PRODUCT_NAME:rfc1034identifier)"; 636 | PRODUCT_NAME = "$(TARGET_NAME)"; 637 | SKIP_INSTALL = YES; 638 | SWIFT_VERSION = 3.0; 639 | }; 640 | name = Release; 641 | }; 642 | FBA6AB131AD3EC9F00721644 /* Debug */ = { 643 | isa = XCBuildConfiguration; 644 | buildSettings = { 645 | FRAMEWORK_SEARCH_PATHS = ( 646 | "$(SDKROOT)/Developer/Library/Frameworks", 647 | "$(inherited)", 648 | ); 649 | GCC_PREPROCESSOR_DEFINITIONS = ( 650 | "DEBUG=1", 651 | "$(inherited)", 652 | ); 653 | INFOPLIST_FILE = RichEditorViewTests/Info.plist; 654 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 655 | PRODUCT_BUNDLE_IDENTIFIER = "com.cjwirth.$(PRODUCT_NAME:rfc1034identifier)"; 656 | PRODUCT_NAME = "$(TARGET_NAME)"; 657 | SWIFT_VERSION = 3.0; 658 | }; 659 | name = Debug; 660 | }; 661 | FBA6AB141AD3EC9F00721644 /* Release */ = { 662 | isa = XCBuildConfiguration; 663 | buildSettings = { 664 | FRAMEWORK_SEARCH_PATHS = ( 665 | "$(SDKROOT)/Developer/Library/Frameworks", 666 | "$(inherited)", 667 | ); 668 | INFOPLIST_FILE = RichEditorViewTests/Info.plist; 669 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 670 | PRODUCT_BUNDLE_IDENTIFIER = "com.cjwirth.$(PRODUCT_NAME:rfc1034identifier)"; 671 | PRODUCT_NAME = "$(TARGET_NAME)"; 672 | SWIFT_VERSION = 3.0; 673 | }; 674 | name = Release; 675 | }; 676 | /* End XCBuildConfiguration section */ 677 | 678 | /* Begin XCConfigurationList section */ 679 | FBA6AAF31AD3EC9F00721644 /* Build configuration list for PBXProject "RichEditorView" */ = { 680 | isa = XCConfigurationList; 681 | buildConfigurations = ( 682 | FBA6AB0D1AD3EC9F00721644 /* Debug */, 683 | FBA6AB0E1AD3EC9F00721644 /* Release */, 684 | ); 685 | defaultConfigurationIsVisible = 0; 686 | defaultConfigurationName = Release; 687 | }; 688 | FBA6AB0F1AD3EC9F00721644 /* Build configuration list for PBXNativeTarget "RichEditorView" */ = { 689 | isa = XCConfigurationList; 690 | buildConfigurations = ( 691 | FBA6AB101AD3EC9F00721644 /* Debug */, 692 | FBA6AB111AD3EC9F00721644 /* Release */, 693 | ); 694 | defaultConfigurationIsVisible = 0; 695 | defaultConfigurationName = Release; 696 | }; 697 | FBA6AB121AD3EC9F00721644 /* Build configuration list for PBXNativeTarget "RichEditorViewTests" */ = { 698 | isa = XCConfigurationList; 699 | buildConfigurations = ( 700 | FBA6AB131AD3EC9F00721644 /* Debug */, 701 | FBA6AB141AD3EC9F00721644 /* Release */, 702 | ); 703 | defaultConfigurationIsVisible = 0; 704 | defaultConfigurationName = Release; 705 | }; 706 | /* End XCConfigurationList section */ 707 | }; 708 | rootObject = FBA6AAF01AD3EC9F00721644 /* Project object */; 709 | } 710 | --------------------------------------------------------------------------------