---
title: 'Copycopter: Introducing a Simpler Way to Edit Copy'
teaser:
tags: news,web,copycopter
author: Joe Ferris
published_on: 2011-06-14
---

Around four months ago we
[launched](https://thoughtbot.com/blog/post/3201164937/introducing-copycopter)
our service for managing copy text in web applications:
[Copycopter](https://copycopter.com). If you're already riding the choppa,
you've probably noticed steady improvements in the user interface. Today, we
rolled out another change to make things nicer for non-technical users that want
to edit copy text: a simpler editor.

## What you see is what you get

We've done a lot to keep Copycopter simple to use. However, we also didn't want
to limit developers and designers by enforcing a limited language like textile,
so we stuck to good old HTML. The draw back of this approach is that
nontechnical users were occasionally confused by the markup in the copy text
they wanted to edit. Worse, it was easy for such a user to break the page by
accidentally changing the <abbr title="HyperText Markup Language">HTML</abbr> to
be invalid. We didn't think it was acceptable for every user to be one "&lt;"
away from a broken page, so we changed this:

![HTML editor](http://images.thoughtbot.com/ui/edit_html.png)

To this:

![Simple editor](http://images.thoughtbot.com/ui/edit_simple.png)

If you'd rather see <abbr title="HyperText Markup Language">HTML</abbr>, don't
worry - we're not leaving anyone out in the cold. One click will bring you back
to the <abbr title="HyperText Markup Language">HTML</abbr> editor you know and
love:

![Switch editor mode](http://images.thoughtbot.com/ui/switch_editor.png)

We used the excellent [jwysiwyg](https://github.com/akzhan/jwysiwyg/wiki)
library to create our simple editor. Getting the editor up and running was easy,
but making our integration tests work with the editor to ensure that it
continued to work was a bit of a challenge.

## TDDWYSIWYG

We used Cucumber to make sure that users could apply formatting to blurbs:

    @javascript
    Scenario: Apply formatting to blurbs
      Given the following blurb exists:
        | project         | key      | draft content |
        | name: Breakfast | test.key | <p>hello</p>  |
      When I go to the edit blurb page for "test.key" on "Breakfast"
      And I apply the "bold" editor function to "ell"
      And I apply the "italic" editor function to "el"
      And I press "Save Blurb"
      And I go to the blurbs index for the "Breakfast" project
      Then I should see "<p>h<b><i>el_l</i></b>o</p>"

To apply editor functions, we use this step:

    When /^I apply the "([^"]+)" editor function to "([^"]+)"$/ do |function, selection|
      steps %{
        When I select "#{selection}" from the editor
        And I click the "#{function}" editor button
        And I unfocus the editor
      }
    end

The secret sauce there is being able to select text. We used
[capybara-webkit](https://github.com/thoughtbot/capybara-webkit) to run
Javascript scenarios in Copycopter, so we can use the DOM range and selection
API:

    When /^I select "([^"]+)" from the editor$/ do |text|
      within_editor do
        page.execute_script(<<-JS)
          var xpath = "//*/child::text()[contains(., '#{text}')]";
          var node = document.evaluate(xpath, document, null, XPathResult. ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
          if (!node)
            throw("Couldn't find text to select");
          var start = node.data.indexOf('#{text}');
          var end = start + #{text.size};
          var selection = window.getSelection();
          var range = window.document.createRange();
          range.setStart(node, start);
          range.setEnd(node, end);
          selection.removeAllRanges();
          selection.addRange(range);
        JS
      end
    end

The `within_editor` method selects the iframe created by jwysiwyg, which is
possible because of Aaron Gibralter's contributions to capybara-webkit. We have
several other scenarios for switching modes, handling newlines, and so on.

If you want to see our new editor in action, you should [check out Copycopter](https://copycopter.com)!
