VersionOne API 101: An Agile User Story Editor in 101 Lines
(Comment-free version)
Build a simple, open-source agile user story editor in exactly 101 lines of JavaScript 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.
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>Backbone-Fortified VersionOne Story Editor</title>
</head>
<body>
<h1>Backbone-Fortified VersionOne Story Editor</h1>
<div id="editor">
<form id="editorForm">
<h4>Story Details</h4>
<hr />
<div id="editorFields"></div>
</form>
<button id="storySave">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 you don't know another...)
<br />
<button id="storyLoad">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 #00008B;
background: #F5F5F5;
display: none;
}
h4 {
color: #666;
font-style: italic;
}
label {
color: #00008B;
}
textarea {
height: 100px;
}
#message {
margin-top: 5px;
color: #006400;
}
#storyIdLabel {
font-weight: 700;
}
#message {
display: none;
font-weight: 700;
color: #006400;
}
#error {
display: none;
font-weight: 700;
color: red;
}
JavaScript
var StoryFormSchema = { // Backbone.Form will generate an HTML form based on this schema
Name: { validators: ['required'] }, // Name is required
Description: 'TextArea', // Since these next three are not required, we only need the data type
Benefits: 'TextArea',
Estimate: 'Number',
RequestedBy: {} // Defaults to 'Text'
};
var storyForm = null; // Instance of the schema declared above, created when we click 'Load Story'
var urlRoot = 'http://eval.versionone.net/platformtest/rest-1.v1/Data/Story/'; // V1 API URL base
var headers = { Authorization: 'Basic ' + btoa('admin:admin'), Accept: 'haljson' }; // Headers for auth and accept type format
Backbone.emulateHTTP = true; // Tells Backbone to issue a POST instead of a PUT HTTP method for updates
// Note that Models usually align with addressable HTTP resources, such as '/rest-1.v1/Data/Story/1154'
var StoryModel = Backbone.Model.extend({ // .extend comes from Underscore.js, for created an 'inherited' class
urlRoot: urlRoot, // Sets the root url to the VP API URL base
url: function () { // Override the built in url() for two cases:
if (this.hasChanged() && !this.isNew()) return this.urlRoot + this.id; // In this case, just use the id -- used for save() via POST
return this.urlRoot + this.id + '?sel=' + _.keys(storyForm.schema).join(','); // Otherwise, limit the attributes return to just what our form schema contains
}, // Note that _.keys is another Underscore goody that returns an array of key names from an object
fetch: function(options) { // Overrides the base fetch so we can customize behavior to be V1 API friendly
options || (options = {}); // When no options passed, default to an empty object
_.defaults(options, {dataType: 'json', headers: headers}); // Copies values from 2nd arg into the 1st if-and-only-if they don't exist already in the 1st
return Backbone.Model.prototype.fetch.call(this, options); // Delegate to the base implementation
},
save: function(attributes,...