commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / packages / backbone-forms / src / field.js
1
2 //==================================================================================================
3 //FIELD
4 //==================================================================================================
5
6 Form.Field = (function() {
7
8 var helpers = Form.helpers,
9 templates = Form.templates;
10
11 return Backbone.View.extend({
12
13 /**
14 * @param {Object} Options
15 * Required:
16 * key {String} : The model attribute key
17 * Optional:
18 * schema {Object} : Schema for the field
19 * value {Mixed} : Pass value when not using a model. Use getValue() to get out value
20 * model {Backbone.Model} : Use instead of value, and use commit().
21 * idPrefix {String} : Prefix to add to the editor DOM element's ID
22 */
23 /**
24 * Creates a new field
25 *
26 * @param {Object} options
27 * @param {Object} [options.schema] Field schema. Defaults to { type: 'Text' }
28 * @param {Model} [options.model] Model the field relates to. Required if options.data is not set.
29 * @param {String} [options.key] Model key/attribute the field relates to.
30 * @param {Mixed} [options.value] Field value. Required if options.model is not set.
31 * @param {String} [options.idPrefix] Prefix for the editor ID. By default, the model's CID is used.
32 *
33 * @return {Field}
34 */
35 initialize: function(options) {
36 options = options || {};
37
38 this.form = options.form;
39 this.key = options.key;
40 this.value = options.value;
41 this.model = options.model;
42
43 //Turn schema shorthand notation (e.g. 'Text') into schema object
44 if (_.isString(options.schema)) options.schema = { type: options.schema };
45
46 //Set schema defaults
47 this.schema = _.extend({
48 type: 'Text',
49 title: helpers.keyToTitle(this.key),
50 template: 'field'
51 }, options.schema);
52 },
53
54
55 /**
56 * Provides the context for rendering the field
57 * Override this to extend the default context
58 *
59 * @param {Object} schema
60 * @param {View} editor
61 *
62 * @return {Object} Locals passed to the template
63 */
64 renderingContext: function(schema, editor) {
65 return {
66 key: this.key,
67 title: schema.title,
68 id: editor.id,
69 type: schema.type,
70 editor: '<b class="bbf-tmp-editor"></b>',
71 help: '<b class="bbf-tmp-help"></b>',
72 error: '<b class="bbf-tmp-error"></b>'
73 };
74 },
75
76
77 /**
78 * Renders the field
79 */
80 render: function() {
81 var schema = this.schema,
82 templates = Form.templates;
83
84 //Standard options that will go to all editors
85 var options = {
86 form: this.form,
87 key: this.key,
88 schema: schema,
89 idPrefix: this.options.idPrefix,
90 id: this.getId()
91 };
92
93 //Decide on data delivery type to pass to editors
94 if (this.model) {
95 options.model = this.model;
96 } else {
97 options.value = this.value;
98 }
99
100 //Decide on the editor to use
101 var editor = this.editor = helpers.createEditor(schema.type, options);
102
103 //Create the element
104 var $field = $(templates[schema.template](this.renderingContext(schema, editor)));
105
106 //Remove <label> if it's not wanted
107 if (schema.title === false) {
108 $field.find('label[for="'+editor.id+'"]').first().remove();
109 }
110
111 //Render editor
112 $field.find('.bbf-tmp-editor').replaceWith(editor.render().el);
113
114 //Set help text
115 this.$help = $('.bbf-tmp-help', $field).parent();
116 this.$help.empty();
117 if (this.schema.help) this.$help.html(this.schema.help);
118
119 //Create error container
120 this.$error = $($('.bbf-tmp-error', $field).parent()[0]);
121 if (this.$error) this.$error.empty();
122
123 //Add custom CSS class names
124 if (this.schema.fieldClass) $field.addClass(this.schema.fieldClass);
125
126 //Add custom attributes
127 if (this.schema.fieldAttrs) $field.attr(this.schema.fieldAttrs);
128
129 //Replace the generated wrapper tag
130 this.setElement($field);
131
132 return this;
133 },
134
135 /**
136 * Creates the ID that will be assigned to the editor
137 *
138 * @return {String}
139 */
140 getId: function() {
141 var prefix = this.options.idPrefix,
142 id = this.key;
143
144 //Replace periods with underscores (e.g. for when using paths)
145 id = id.replace(/\./g, '_');
146
147 //If a specific ID prefix is set, use it
148 if (_.isString(prefix) || _.isNumber(prefix)) return prefix + id;
149 if (_.isNull(prefix)) return id;
150
151 //Otherwise, if there is a model use it's CID to avoid conflicts when multiple forms are on the page
152 if (this.model) return this.model.cid + '_' + id;
153
154 return id;
155 },
156
157 /**
158 * Check the validity of the field
159 *
160 * @return {String}
161 */
162 validate: function() {
163 var error = this.editor.validate();
164
165 if (error) {
166 this.setError(error.message);
167 } else {
168 this.clearError();
169 }
170
171 return error;
172 },
173
174 /**
175 * Set the field into an error state, adding the error class and setting the error message
176 *
177 * @param {String} msg Error message
178 */
179 setError: function(msg) {
180 //Object and NestedModel types set their own errors internally
181 if (this.editor.hasNestedForm) return;
182
183 var errClass = Form.classNames.error;
184
185 this.$el.addClass(errClass);
186
187 if (this.$error) {
188 this.$error.html(msg);
189 } else if (this.$help) {
190 this.$help.html(msg);
191 }
192 },
193
194 /**
195 * Clear the error state and reset the help message
196 */
197 clearError: function() {
198 var errClass = Form.classNames.error;
199
200 this.$el.removeClass(errClass);
201
202 // some fields (e.g., Hidden), may not have a help el
203 if (this.$error) {
204 this.$error.empty();
205 } else if (this.$help) {
206 this.$help.empty();
207
208 //Reset help text if available
209 var helpMsg = this.schema.help;
210 if (helpMsg) this.$help.html(helpMsg);
211 }
212 },
213
214 /**
215 * Update the model with the new value from the editor
216 */
217 commit: function() {
218 return this.editor.commit();
219 },
220
221 /**
222 * Get the value from the editor
223 *
224 * @return {Mixed}
225 */
226 getValue: function() {
227 return this.editor.getValue();
228 },
229
230 /**
231 * Set/change the value of the editor
232 *
233 * @param {Mixed} value
234 */
235 setValue: function(value) {
236 this.editor.setValue(value);
237 },
238
239 focus: function() {
240 this.editor.focus();
241 },
242
243 blur: function() {
244 this.editor.blur();
245 },
246
247 /**
248 * Remove the field and editor views
249 */
250 remove: function() {
251 this.editor.remove();
252
253 Backbone.View.prototype.remove.call(this);
254 }
255
256 });
257
258 })();