Stephen Haney

Get contenteditable plaintext with correct linebreaks

What do you do if you need plaintext from a contenteditable HTML element with correct linebreaks?

It should be simple – just use element.innerText.

But TIL there are bugs with contenteditable and innerText linebreaks. For me, Chrome reports too many linebreaks. And I’m finding reports of FireFox doing the same.

// What my content editable looks like, a single line between


// What Chrome innerText reports, two lines between


I created a reproduction case codepen here, type type “a -> return -> return -> b” in the left and you’ll see the wrong result pop up on the right hand side (unless it’s been fixed by now!)

Where did this come from?

The problem, it seems, originates from browsers making up their own HTML for contenteditable. Some use divs, some use p tags, others prefer br. Chrome seems to mix and match divs and br elements even now.

No wonder innerText returns the wrong result – it’s hard to parse unpredictable HTML!

It sounds like browsers have tried to align on a standard for contenteditable HTML… my guess is that those efforts broke the innerText linebreak parsing without anyone noticing.

There’s a great history on MDN if you’d like more info.

A solution emerges

Ok, so what do we do for now if we need a plaintext value but also need perfect linebreaks?

Here is a snippet I’m using – it’s working but I haven’t tried to account for use cases beyond my own. So… apply it with your own critical thinking.

let newValue = '';
let isOnFreshLine = true;

// Recursive function to navigate childNodes and build linebreaks with text
function parseChildNodesForValueAndLines(childNodes: NodeListOf<ChildNode>) {
  for (let i = 0; i < childNodes.length; i++) {
    const childNode = childNodes[i];

    if (childNode.nodeName === 'BR') {
      // BRs are always line breaks which means the next loop is on a fresh line
      newValue += '\n';
      isOnFreshLine = true;

    // We may or may not need to create a new line
    if (childNode.nodeName === 'DIV' && isOnFreshLine === false) {
      // Divs create new lines for themselves if they aren't already on one
      newValue += '\n';

    // Whether we created a new line or not, we'll use it for this content so the next loop will not be on a fresh line:
    isOnFreshLine = false;

    // Add the text content if this is a text node:
    if (childNode.nodeType === 3 && childNode.textContent) {
      newValue += childNode.textContent;

    // If this node has children, get into them as well:

// Parse the child nodes for HTML and newlines:

// Do whatever you want with newValue now

You’ll also need `white-space: ‘pre-wrap’` set on your elements to preserve your linebreaks.

In testing that, I’ve another found issue in Safari where a single unbreakable word that’s too wide for its element will render with an extra incorrect linebreak – but not when contenteditable is set! But that’s an issue for another day.

I hope this experience helps someone else who stumbles upon this problem.

React Styled Components in IFrames

How can you use Styled Components inside an IFrame? It took some research, but I found an elegant solution using styled-components and react-frame-component.

Happily, styled-components includes a StyleSheetManager component that can take a target prop. The target expects a DOM node, and it will attach its dynamically created stylesheets to that node.

react-frame-component uses React’s new version of its Context API to expose a FrameContextProvider. It includes the IFrame document and window in the context.

You can combine these two APIs as follows to use styled-components inside your IFrames:

      frameContext => (
        <StyleSheetManager target={frameContext.document.head}>
            {/* your children here */}

This works perfectly with react v16.4.1, styled-components v3.3.3, and react-frame-component v4.0.0.

How to Add Interstitial iAds in SpriteKit with Swift

I recently implemented interstitial iAds for the first time in Swift. I want to share my implementation of interstitial iAds, since I found the current google-sphere a bit lacking (at least in Swift). You’ll need to do some initial work in iTunes Connect to get your iOS app ready for iAds. Once you are ready, you can base your iAds integration on my example.

Implement interstitial iAds into your SpriteKit game

A test interstitial iAd successfully displayed in the iOS emulator

I chose to create a new SKScene to serve as a transition between my menu and game scenes. This transition scene displays the iAd interstitial and uses this time to preload and cache my game textures (the first time through the scene). I attach the iAd interstitial as a sub view on this transition scene’s parent view. We’ll also create our own UIButton to close the interstitial ad, as I show below.

First, import iAd into your file:

import iAd

Second, adhere to the ADInterstitialAdDelegate protocol in your class definition. This allows us to get callbacks after the interstitial iAds close.

class TransitionScene : SKScene, ADInterstitialAdDelegate {

Third, create these properties on the TransitionScene class:

    var interAd:ADInterstitialAd?
    var interAdView = UIView()
    var closeButton = UIButton.buttonWithType(UIButtonType.System) as! UIButton

Fourth, configure the close button in the TransitionScene didMoveToView function:

override func didMoveToView(view: SKView) {
    // Define a close button size:
    closeButton.frame = CGRectMake(20, 20, 70, 44)
    closeButton.layer.cornerRadius = 10
    // Give the close button some coloring layout:
    closeButton.backgroundColor = UIColor.whiteColor()
    closeButton.layer.borderColor = UIColor.blackColor().CGColor
    closeButton.layer.borderWidth = 1
    closeButton.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
    // Wire up the closeAd function when the user taps the button
    closeButton.addTarget(self, action: "closeAd:", forControlEvents: UIControlEvents.TouchDown)
    // Some funkiness to get the title to display correctly every time:
    closeButton.enabled = false
    closeButton.setTitle("skip", forState: UIControlState.Normal)
    closeButton.enabled = true

Fifth, implement these functions in your TransitionScene class:

// iAd
func prepareAd() {
    println(" --- AD: Try Load ---")
    // Attempt to load a new ad:
    interAd = ADInterstitialAd()
    interAd?.delegate = self

// You can call this function from an external source when you actually want to display an ad:
func showAd() -> Bool {
    if interAd != nil && interAd!.loaded {
        interAdView = UIView()
        interAdView.frame = self.view!.bounds
    // Return true if we're showing an ad, false if an ad can't be displayed:
    return interAd?.loaded ?? false

// When the user clicks the close button, route to the adFinished function:
func closeAd(sender: UIButton) {

// A function of common functionality to run when the user returns to your app:
func adFinished() {
    // (Do whatever is next in your app)

// The ad loaded successfully (we don't need to do anything for the basic implementation)
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
    println(" --- AD: Load Success ---")

// The ad unloaded (we don't need to do anything for the basic implementation)
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
    println(" --- AD: Unload --- ")

// This is called if the user clicks into the interstitial, and then finishes interacting with the ad
// We'll call our adFinished function since we're returning to our app:
func interstitialAdActionDidFinish(interstitialAd: ADInterstitialAd!) {
    println(" --- ADD: Action Finished --- ")

func interstitialAdActionShouldBegin(interstitialAd: ADInterstitialAd!, willLeaveApplication willLeave: Bool) -> Bool {
    return true

// Error in the ad load, print out the error
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
    println(" --- AD: Error --- ")

Sixth, call your new prepareAd function to load a new ad. I’ll often create an instance of the TransitionScene in a separate scene (like my GameScene) so I can load ads before I need to show them (for instance: as soon as the player dies, but before they click new game).

Create an instance of your TransitionScene in the GameScene (or wherever you need it) and then call prepareAd a few moments before you’ll need the transition:


Finally, in your GameScene (or wherever you are) present the transitionScene instance:

self.view?.presentScene(transitionScene, transition: .crossFadeWithDuration(0.6))

You can call your new showAd function from within the TransitionScene whenever you want the interstitial iAd to show. If you want it to show as soon as the transition scene starts, add the following code to your TransitionScene didMoveToView function:

// Try to show an ad
let adShown = showAd()

// If no ad, just move on
if adShown == false {
    // Do whatever's next for your app

I hope that helps you implement interstitial iAds into your SpriteKit Swift app. Leave me a comment if you need any help putting this to use. Cheers!

SKSpriteNodes anchorPoint in Swift and SpriteKit

Note: This is a free excerpt from my new book, Game Development with Swift. If you like this post, you’ll love the book! The book walks you through the creation of a 2D iOS game from start to publication on the App Store. So far, I’ve received nothing but great feedback from readers. Check out my new Swift SpriteKit book on Amazon

SpriteKit uses a grid of points to position nodes. In this grid, the bottom left corner of the scene is (0,0), with a positive X-axis to the right and a positive Y-axis to the top. Similarly, on the individual sprite level, (0,0) refers to the bottom left corner of the sprite, while (1,1) refers to the top right corner.

Alignment with Anchor Points

Each sprite has an anchor point property, or an origin. The anchorPoint property allows you to choose which part of the sprite aligns to the sprite’s overall position.

The default anchor point is (0.5,0.5), so new SKSpriteNodes center perfectly on their position.

Upside Down SKPhysicsBody when Loaded From Texture

I ran into an odd SpriteKit bug the other day when preloading and caching my texture atlases. It seems that you cannot create more than one SKPhysicsBody from a single instance of a texture, or all subsequent physics bodies will be created upside down. This StackOverflow thread suggests it’s an issue with internally cached textures.

Building an SKPhysicsBody from a cached texture creates inverted physics bodies

Building an SKPhysicsBody from a cached texture creates inverted physics bodies


Game Development with Swift Released!

Late last night I received an email from my publisher: Game Development with Swift is officially published! It is so exciting to have my work out in the world, helping people learn a fun skill. I can’t wait for feedback and to see some of the games the readers create. If you are interested in SpriteKit, Swift, or any 2D game development on iPhone, iPad, and iOS in general, check it out!

Read the Amazon Game Development with Swift page

. . . or the Publisher Game Development with Swift page

Event Triggers and Event Listeners in Swift, Updated Swift 6.2

I recently updated my mini-library that adds Backbone.js style listeners and triggers to Swift. I improved the ability to pass information between triggers and listeners, and updated the syntax for Swift 6.2, using Xcode 6.3 beta 2. Using custom events is a pretty nifty way of organizing your Swift project.


Download it here: Swift Custom Events on GitHub


Here’s an example of how Swift Custom Events works:

Let’s create a cat class that can bug us while we’re coding:

class Cat {
    let events = EventManager();

    func meow() {
        println("Cat: MRaawwweeee");"meow", information: "The cat is hungry!");


Saving SpriteKit Game Data in Swift – It’s Easy with NSCoder

Saving SpriteKit game information on iOS is a common requirement. We need to save the player’s progress, preferences, and high scores. I recently implemented a high score system for Krate. Though this Swift code is tailored for score keeping, it can be easily adapted to persist save game data or any other information you need to save between games.

We’ll inherit NSCoder to serialize our objects, then store the data using one of several iOS data persistence methods. I chose to save my high score data using plist files, saved inside my game’s directory. (You can also use NSUserDefaults to store serialized objects, though it is intended only for user preferences. Another option is Core Data, which is robust and useful for complicated Swift persistence tasks.)

First off, we’ll need a serializable class that will store our save game data. NSCoding allows us to translate our class into data that can be saved to the file system.

// inherit from NSCoding to make instances serializable
class HighScore: NSObject, NSCoding {
    let score:Int;
    let dateOfScore:NSDate;
    init(score:Int, dateOfScore:NSDate) {
        self.score = score;
        self.dateOfScore = dateOfScore;
    required init(coder: NSCoder) {
        self.score = coder.decodeObjectForKey("score")! as Int;
        self.dateOfScore = coder.decodeObjectForKey("dateOfScore")! as NSDate;
    func encodeWithCoder(coder: NSCoder) {
        coder.encodeObject(self.score, forKey: "score")
        coder.encodeObject(self.dateOfScore, forKey: "dateOfScore")

Great! Next, we want to create a manager class to store an array of HighScores, and perform the save action. Mind the comments – the code required to save and read plist files is long:

class HighScoreManager {
    var scores:Array<HighScore> = [];
    init() {
        // load existing high scores or set up an empty array
        let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        let documentsDirectory = paths[0] as String
        let path = documentsDirectory.stringByAppendingPathComponent("HighScores.plist")
        let fileManager = NSFileManager.defaultManager()
        // check if file exists
        if !fileManager.fileExistsAtPath(path) {
            // create an empty file if it doesn't exist
            if let bundle = NSBundle.mainBundle().pathForResource("DefaultFile", ofType: "plist") {
                fileManager.copyItemAtPath(bundle, toPath: path, error:nil)
        if let rawData = NSData(contentsOfFile: path) {
            // do we get serialized data back from the attempted path?
            // if so, unarchive it into an AnyObject, and then convert to an array of HighScores, if possible
            var scoreArray: AnyObject? = NSKeyedUnarchiver.unarchiveObjectWithData(rawData);
            self.scores = scoreArray as? [HighScore] ?? [];
    func save() {
        // find the save directory our app has permission to use, and save the serialized version of self.scores - the HighScores array.
        let saveData = NSKeyedArchiver.archivedDataWithRootObject(self.scores);
        let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray;
        let documentsDirectory = paths.objectAtIndex(0) as NSString;
        let path = documentsDirectory.stringByAppendingPathComponent("HighScores.plist");
        saveData.writeToFile(path, atomically: true);
    // a simple function to add a new high score, to be called from your game logic
    // note that this doesn't sort or filter the scores in any way
    func addNewScore(newScore:Int) {
        let newHighScore = HighScore(score: newScore, dateOfScore: NSDate());

We can persist any type of game data we need with this same pattern . . . and though the code to write and read plist files is a bit verbose, the concept is actually quite straightforward. Kindly leave a comment with any questions or suggestions.

A quick note of credit: thanks to this blog post for solid plist persistence info.

Raise the Skill Cap by Hinting at Upcoming Events

krate iphone game colors hud update

The HUD now displays the next 3 colors for the player.

One of my concerns with Krate is that I would end up with a game that came down to luck more than skill. One of my goals is to make the game re-playable because there’s potential for growth. I want a high “skill cap”, such that a talented player will end up with a dramatically better result than a casual player. One example of a low skill cap was the Paladin class in early WoW. They were very beginner friendly, with only a few buttons to press. The downside was that an experienced player couldn’t perform much better than a beginner. DOTA2 is another game with a mix of low skill cap (drow ranger) and high skill cap (meepo) heroes. With each decision I make, I try to think “will this raise or lower the skill cap?” because I believe a high skill cap gives an authentic reason for the player to replay the game.

Strategy through Information

I want the player to be actively planning and strategizing while playing Krate. Players have a chance to plan and react well or poorly to each game event. Players can better plan if I make sure to give plenty of information. One way I found to do this is to show the upcoming colors that the player will place. Originally, I was only showing the active color to be placed, and I found I wasn’t planning much, but simply reacting to each new color assignment. I built out a system to display the next 3 colors and I think it’s added a lot to the game’s strategy. Check out the video with the new color assignment HUD:


Swift Events: Create Triggers and Listeners in Swift

Backbone includes an elegant and awesome events system that allows for some beautiful code organization in web apps. The events system lets you put your code where it belongs, rather than being tied in to a bunch of function calls in the event trigger. You can add and remove functionality from different events as well. It’s especially useful for game systems like keeping track of events that count towards achievements.

I wanted this functionality for Krate, my iPhone puzzle game, so I wrote a fast solution that mimics the most usable parts of Backbone’s system for custom Swift events triggering.

You can find it here: Swift Events on GitHub. There’s some examples and more information on using the class. Give it a try and let me know how you like it – it’s very usable right now, but I’m definitely open to feedback and improvements.