Bootstrap form example

by JoshGough

HTML

<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script src="https://raw.github.com/versionone/VersionOne.Requestor.NET/master/VersionOne.Requestor.NET.Backbone/Scripts/backbone-v1.js"></script>
<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>VersionOne MetaMorformizer Story Editor</title>
    </head>
    
    <body>
        	<h1>VersionOne MetaMorformizer Story Editor</h1>
An intermediate / advanced example of using the VersionOne HTTP API with
        the open source jQuery, Backbone, and Backbone Forms libraries.
        <br/>
        <br/>This example uses all three core VersionOne APIs: Meta, Localization,
        and Data.
        <a href="http://community.versionone.com/sdk/documentation/coreapi.aspx"
        target="_blank">Learn more here about the APIs</a>.
        <br/>
        <br/>
        <div style='border: 1px solid darkgray;padding:5px;background:linen'>
             <h3>Instructions</h3>

            <ol>
                <li>1: Click <code>Load Story</code>

                    <br/>
                    <blockquote><i><span>Result</span>: Story details should load with values for the attributes selected in the <code>Which attributes?</code> list</i>
                    </blockquote>
                </li>
                <li>2: Modify the story and click <code>Save Story</code>

                    <br/>
                    <blockquote><i><span>Result</span>: Story will be saved...

CSS

body {
    padding: 5px;
    font-family: sans-serif;
}
#editor {
    padding: 10px;
    border: 1px solid darkblue;
    background: whitesmoke;
    display: none;
    margin-bottom: 15px;
}
label { color: darkblue }
textarea { height: 100px }
#message {
    font-weight: bold;
    color: darkgreen;
}
/* From Backbone Forms github site */
/* Date */
.bbf-date .bbf-date { width: 4em }
.bbf-date .bbf-month { width: 9em }
.bbf-date .bbf-year { width: 5em }
/* DateTime */
.bbf-datetime select { width: 4em }
/* List */
.bbf-list .bbf-add,
.bbf-load { margin-top: -10px }
.bbf-list li { margin-bottom: 5px }
.bbf-list .bbf-del { margin-left: 4px }
/* List.Modal */
.bbf-list-modal {
    cursor: pointer;
    border: 1px solid #ccc;
    width: 208px;
    border-radius: 3px;
    padding: 4px;
    color: #555;
}
/* Custom */
#spinner,
#saveSpinner { display: none }
blockquote {
    font-size: 75%;
    font-weight: bold;
}
blockquote code {
    font-size: 75%;
    background: beige;
}
blockquote span { color: darkgreen }
.editorDiv {
    margin-top: 10px;
    padding: 10px;
    border: 2px solid darkgray;
}

JavaScript

// This simulates getting field names from the query string:
function qs(key) {
    return 'Name,Description,Estimate';
}

Backbone.emulateHTTP = true; // Force backbone to use POST, not PUT on .save(...)

var siteRoot = 'http://eval.versionone.net/platformtest/';
var urlRoot = siteRoot + 'rest-1.v1/Data/Story/';
var metaUrl = siteRoot + 'meta.v1/Story?accept=application/json';
var l10nUrl = siteRoot + 'loc.v1';

var v1AtttributeTypeToBackboneFormsFieldMap = {
    'LongText': {
        type: 'TextArea'
    },
    'Text': {
        type: 'Text'
    },
    'Numeric': {
        type: 'Text',
        validators: [/^\d+$/]
    }
};

var headers = {
    Authorization: "Basic " + btoa("admin:admin"),
    Accept: 'haljson'
};

var fetchOptions = {
    dataType: 'json',
    headers: headers
};

var saveOptions = {
    contentType: 'haljson',
    patch: true,
    headers: headers
    /*
    setXHttpMethodOverride: function(xhr, name, value) {
        xhr.setRequestHeader(name, value);
        console.log(name + ': ' + value);
    }
    */
};

var formSchema = {};
var form = null;
var storyModel = Backbone.Model.extend({
    urlRoot: urlRoot,
    url: function () {
        if (!this.isNew()) return this.urlRoot + this.id;
        return this.urlRoot + this.id + '?sel=' + _.keys(formSchema).join(',');
    },
    save: function (attributes, options) {
        options || (options = saveOptions);
        return Backbone.Model.prototype.save.call(this, attributes, options);
    },
    fetch: function (options) {
        options || (options = fetchOptions);
        return Backbone.Model.prototype.fetch.call(this, options);
    }
});
var model = new storyModel();

function loadMeta(callback) {
    formSchema = {}; // reset the schema
    var attributes = getSelectedAttributesNames();
    $.ajax(metaUrl).done(function (data) {
        var titleRequests = [];
        var attributeNames = _.map(attributes, function (fieldName) {
            return "Story." + fieldName;
        });
  ...