(function() {
rivets.binders.input = {
publishes: true,
routine: rivets.binders.value.routine,
bind: function(el) {
return el.addEventListener('input', this.publish);
},
unbind: function(el) {
return el.removeEventListener('input', this.publish);
}
};
rivets.configure({
prefix: "rv",
adapter: {
subscribe: function(obj, keypath, callback) {
callback.wrapped = function(m, v) {
return callback(v);
};
return obj.on('change:' + keypath, callback.wrapped);
},
unsubscribe: function(obj, keypath, callback) {
return obj.off('change:' + keypath, callback.wrapped);
},
read: function(obj, keypath) {
if (keypath === "cid") {
return obj.cid;
}
return obj.get(keypath);
},
publish: function(obj, keypath, value) {
if (obj.cid) {
return obj.set(keypath, value);
} else {
return obj[keypath] = value;
}
}
}
});
}).call(this);
(function() {
var Formbuilder;
Formbuilder = (function() {
Formbuilder.helpers = {
defaultFieldAttrs: function(field_type) {
var attrs, _base;
attrs = {
label: "Untitled",
field_type: field_type,
required: true,
field_options: {}
};
return (typeof (_base = Formbuilder.fields[field_type]).defaultAttributes === "function" ? _base.defaultAttributes(attrs) : void 0) || attrs;
},
simple_format: function(x) {
return x != null ? x.replace(/\n/g, '
') : void 0;
}
};
Formbuilder.options = {
BUTTON_CLASS: 'fb-button',
HTTP_ENDPOINT: '',
HTTP_METHOD: 'POST',
mappings: {
SIZE: 'field_options.size',
UNITS: 'field_options.units',
LABEL: 'label',
FIELD_TYPE: 'field_type',
REQUIRED: 'required',
ADMIN_ONLY: 'admin_only',
OPTIONS: 'field_options.options',
DESCRIPTION: 'field_options.description',
INCLUDE_OTHER: 'field_options.include_other_option',
INCLUDE_BLANK: 'field_options.include_blank_option',
INTEGER_ONLY: 'field_options.integer_only',
MIN: 'field_options.min',
MAX: 'field_options.max',
MINLENGTH: 'field_options.minlength',
MAXLENGTH: 'field_options.maxlength',
LENGTH_UNITS: 'field_options.min_max_length_units'
},
dict: {
ALL_CHANGES_SAVED: 'All changes saved',
SAVE_FORM: 'Save form',
UNSAVED_CHANGES: 'You have unsaved changes. If you leave this page, you will lose those changes!'
}
};
Formbuilder.fields = {};
Formbuilder.inputFields = {};
Formbuilder.nonInputFields = {};
Formbuilder.model = Backbone.DeepModel.extend({
sync: function() {},
indexInDOM: function() {
var $wrapper,
_this = this;
$wrapper = $(".fb-field-wrapper").filter((function(_, el) {
return $(el).data('cid') === _this.cid;
}));
return $(".fb-field-wrapper").index($wrapper);
},
is_input: function() {
return Formbuilder.inputFields[this.get(Formbuilder.options.mappings.FIELD_TYPE)] != null;
}
});
Formbuilder.collection = Backbone.Collection.extend({
initialize: function() {
return this.on('add', this.copyCidToModel);
},
model: Formbuilder.model,
comparator: function(model) {
return model.indexInDOM();
},
copyCidToModel: function(model) {
return model.attributes.cid = model.cid;
}
});
Formbuilder.registerField = function(name, opts) {
var x, _i, _len, _ref;
_ref = ['view', 'edit'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
x = _ref[_i];
opts[x] = _.template(opts[x]);
}
Formbuilder.fields[name] = opts;
if (opts.type === 'non_input') {
return Formbuilder.nonInputFields[name] = opts;
} else {
return Formbuilder.inputFields[name] = opts;
}
};
Formbuilder.views = {
view_field: Backbone.View.extend({
className: "fb-field-wrapper",
events: {
'click .subtemplate-wrapper': 'focusEditView',
'click .js-duplicate': 'duplicate',
'click .js-clear': 'clear'
},
initialize: function() {
this.parentView = this.options.parentView;
this.listenTo(this.model, "change", this.render);
return this.listenTo(this.model, "destroy", this.remove);
},
render: function() {
this.$el.addClass('response-field-' + this.model.get(Formbuilder.options.mappings.FIELD_TYPE)).data('cid', this.model.cid).html(Formbuilder.templates["view/base" + (!this.model.is_input() ? '_non_input' : '')]({
rf: this.model
}));
return this;
},
focusEditView: function() {
return this.parentView.createAndShowEditView(this.model);
},
clear: function() {
this.parentView.handleFormUpdate();
return this.model.destroy();
},
duplicate: function() {
var attrs;
attrs = _.clone(this.model.attributes);
delete attrs['id'];
attrs['label'] += ' Copy';
return this.parentView.createField(attrs, {
position: this.model.indexInDOM() + 1
});
}
}),
edit_field: Backbone.View.extend({
className: "edit-response-field",
events: {
'click .js-add-option': 'addOption',
'click .js-remove-option': 'removeOption',
'click .js-default-updated': 'defaultUpdated',
'input .option-label-input': 'forceRender'
},
initialize: function() {
return this.listenTo(this.model, "destroy", this.remove);
},
render: function() {
this.$el.html(Formbuilder.templates["edit/base" + (!this.model.is_input() ? '_non_input' : '')]({
rf: this.model
}));
rivets.bind(this.$el, {
model: this.model
});
return this;
},
remove: function() {
this.options.parentView.editView = void 0;
this.options.parentView.$el.find("[href=\"#addField\"]").click();
return Backbone.View.prototype.remove.call(this);
},
addOption: function(e) {
var $el, i, newOption, options;
$el = $(e.currentTarget);
i = this.$el.find('.option').index($el.closest('.option'));
options = this.model.get(Formbuilder.options.mappings.OPTIONS) || [];
newOption = {
label: "",
checked: false
};
if (i > -1) {
options.splice(i + 1, 0, newOption);
} else {
options.push(newOption);
}
this.model.set(Formbuilder.options.mappings.OPTIONS, options);
this.model.trigger("change:" + Formbuilder.options.mappings.OPTIONS);
return this.forceRender();
},
removeOption: function(e) {
var $el, index, options;
$el = $(e.currentTarget);
index = this.$el.find(".js-remove-option").index($el);
options = this.model.get(Formbuilder.options.mappings.OPTIONS);
options.splice(index, 1);
this.model.set(Formbuilder.options.mappings.OPTIONS, options);
this.model.trigger("change:" + Formbuilder.options.mappings.OPTIONS);
return this.forceRender();
},
defaultUpdated: function(e) {
var $el;
$el = $(e.currentTarget);
if (this.model.get(Formbuilder.options.mappings.FIELD_TYPE) !== 'checkboxes') {
this.$el.find(".js-default-updated").not($el).attr('checked', false).trigger('change');
}
return this.forceRender();
},
forceRender: function() {
return this.model.trigger('change');
}
}),
main: Backbone.View.extend({
SUBVIEWS: [],
events: {
'click .js-save-form': 'saveForm',
'click .fb-tabs a': 'showTab',
'click .fb-add-field-types a': 'addField'
},
initialize: function() {
this.$el = $(this.options.selector);
this.formBuilder = this.options.formBuilder;
this.collection = new Formbuilder.collection;
this.collection.bind('add', this.addOne, this);
this.collection.bind('reset', this.reset, this);
this.collection.bind('change', this.handleFormUpdate, this);
this.collection.bind('destroy add reset', this.hideShowNoResponseFields, this);
this.collection.bind('destroy', this.ensureEditViewScrolled, this);
this.render();
this.collection.reset(this.options.bootstrapData);
return this.initAutosave();
},
initAutosave: function() {
var _this = this;
this.formSaved = true;
this.saveFormButton = this.$el.find(".js-save-form");
this.saveFormButton.attr('disabled', true).text(Formbuilder.options.dict.ALL_CHANGES_SAVED);
setInterval(function() {
return _this.saveForm.call(_this);
}, 5000);
return $(window).bind('beforeunload', function() {
if (_this.formSaved) {
return void 0;
} else {
return Formbuilder.options.dict.UNSAVED_CHANGES;
}
});
},
reset: function() {
this.$responseFields.html('');
return this.addAll();
},
render: function() {
var subview, _i, _len, _ref;
this.$el.html(Formbuilder.templates['page']());
this.$fbLeft = this.$el.find('.fb-left');
this.$responseFields = this.$el.find('.fb-response-fields');
this.bindWindowScrollEvent();
this.hideShowNoResponseFields();
_ref = this.SUBVIEWS;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
subview = _ref[_i];
new subview({
parentView: this
}).render();
}
return this;
},
bindWindowScrollEvent: function() {
var _this = this;
return $(window).on('scroll', function() {
var maxMargin, newMargin;
if (_this.$fbLeft.data('locked') === true) {
return;
}
newMargin = Math.max(0, $(window).scrollTop());
maxMargin = _this.$responseFields.height();
return _this.$fbLeft.css({
'margin-top': Math.min(maxMargin, newMargin)
});
});
},
showTab: function(e) {
var $el, first_model, target;
$el = $(e.currentTarget);
target = $el.data('target');
$el.closest('li').addClass('active').siblings('li').removeClass('active');
$(target).addClass('active').siblings('.fb-tab-pane').removeClass('active');
if (target !== '#editField') {
this.unlockLeftWrapper();
}
if (target === '#editField' && !this.editView && (first_model = this.collection.models[0])) {
return this.createAndShowEditView(first_model);
}
},
addOne: function(responseField, _, options) {
var $replacePosition, view;
view = new Formbuilder.views.view_field({
model: responseField,
parentView: this
});
if (options.$replaceEl != null) {
return options.$replaceEl.replaceWith(view.render().el);
} else if ((options.position == null) || options.position === -1) {
return this.$responseFields.append(view.render().el);
} else if (options.position === 0) {
return this.$responseFields.prepend(view.render().el);
} else if (($replacePosition = this.$responseFields.find(".fb-field-wrapper").eq(options.position))[0]) {
return $replacePosition.before(view.render().el);
} else {
return this.$responseFields.append(view.render().el);
}
},
setSortable: function() {
var _this = this;
if (this.$responseFields.hasClass('ui-sortable')) {
this.$responseFields.sortable('destroy');
}
this.$responseFields.sortable({
forcePlaceholderSize: true,
placeholder: 'sortable-placeholder',
stop: function(e, ui) {
var rf;
if (ui.item.data('field-type')) {
rf = _this.collection.create(Formbuilder.helpers.defaultFieldAttrs(ui.item.data('field-type')), {
$replaceEl: ui.item
});
_this.createAndShowEditView(rf);
}
_this.handleFormUpdate();
return true;
},
update: function(e, ui) {
if (!ui.item.data('field-type')) {
return _this.ensureEditViewScrolled();
}
}
});
return this.setDraggable();
},
setDraggable: function() {
var $addFieldButtons,
_this = this;
$addFieldButtons = this.$el.find("[data-field-type]");
return $addFieldButtons.draggable({
connectToSortable: this.$responseFields,
helper: function() {
var $helper;
$helper = $("
<%= rf.get(Formbuilder.options.mappings.DESCRIPTION) %>
", edit: "
\n \n