VersionOne API 101: An Agile User Story Editor in 101 Lines
Build a simple, open-source agile user story editor in exactly 80 lines of CoffeeScript using Backbone.js, Backbone Forms, jQuery, and the VersionOne REST API! You could easily adapt this to save your user story into any tool of your choice. Note: the same thing takes 101 lines in JavaScript!
by JoshGough
HTML
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<script src="https://raw.github.com/powmedia/backbone-forms/master/distribution/backbone-forms.js"></script>
<script src="https://raw.github.com/powmedia/backbone-forms/master/distribution/editors/list.js"></script>
<script src="https://raw.github.com/powmedia/backbone-forms/master/distribution/adapters/backbone.bootstrap-modal.js"></script>
<script src="https://raw.github.com/powmedia/backbone-forms/master/distribution/templates/bootstrap.js"></script>
<html>
<head>
<title>Barebones Story Editor</title>
</head>
<body>
<h1>Barebones Story Editor</h1>
<div id="editor">
<form id="editorForm">
<h4>Story Details</h4>
<hr />
<div id="editorFields"></div>
</form>
<button id="save">Save Story</button> <span id="message"></span><span id="error"></span>
</div>
<h2>Enter a Story ID</h2>
<input type="text" id="storyId" value="1154" /> (Hint: use 1154 if don't know another...)
<br />
<button id="storyGet">Load Story</button>
<hr/>
Visit the <a href="http://community.versionone.com/default.aspx">VersionOne Community</a> for more open source tools and APIs. Download code and <b>get involved</b> at <a href="http://www.github.com/VersionOne" target="_blank">VersionOne on GitHub</a>!
<br/>
</body>
</html>
CSS
body
{
padding: 5px;
font-family: sans-serif;
}
#editor
{
padding: 10px;
border: 1px solid darkblue;
background: whitesmoke;
display: none;
}
h4 {
color: #666666;
font-style: italic;
}
label
{
color: darkblue;
}
textarea
{
height:100px;
}
#message
{
margin-top: 5px;
color: darkgreen;
}
#storyIdLabel {
font-weight: bold;
}
#message {
display: none;
font-weight: bold;
color: darkgreen;
}
#error {
display: none;
font-weight: bold;
color: red;
}
CoffeeScript
StoryFormSchema =
Name:
validators: ['required']
Description:
type: 'TextArea'
Benefits:
type: 'TextArea'
Estimate:
type: 'Number'
RequestedBy: {}
storyForm = null
urlRoot = 'http://eval.versionone.net/platformtest/rest-1.v1/Data/Story/'
headers =
Authorization: 'Basic ' + btoa('admin:admin')
Accept: 'haljson'
StoryModel = Backbone.Model.extend(
urlRoot: urlRoot
url: ->
return @urlRoot + @id if @hasChanged() and not @isNew()
@urlRoot + @id + '?sel=' + _.keys(storyForm.schema).join(',')
fetch: (options) ->
options or (options = {})
_.defaults options, { dataType: 'json', headers: headers }
Backbone.Model::fetch.call this, options
save: (attributes, options) ->
options or (options = {})
_.defaults options, { contentType: 'haljson', patch: true, headers: headers }
Backbone.Model::save.call this, attributes, options
)
Backbone.emulateHTTP = true
storyModel = new StoryModel
createForm = (model) ->
finish = ->
storyForm = new Backbone.Form(settings)
$('#editorFields').empty()
$('#editorFields').append storyForm.render().el
$('#editor').fadeIn() if model
settings = schema: StoryFormSchema
if model
model.fetch().done (data) ->
settings.model = model
finish()
else
finish()
storyLoad = ->
storyModel.id = $('#storyId').val()
if storyModel.id is ''
alert 'Please enter a story id first'
return
createForm storyModel
storySave = ->
return if storyForm.validate()?
storyForm.commit()
storyModel.save(storyForm.getValue()).done((data) ->
$('#error').hide()
$('#message').text('Story saved!').fadeIn().delay(2500).fadeOut()
).fail (jqXHR) ->
$('#message').hide()
$('#error').text('Error during save! See console for details.').fadeIn().delay(5e3).fadeOut()
console.log jqXHR
$ ->
createForm()
$('#storyGet').click storyLoad
$('#save').click storySave