Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | (function($) { |
2 | if (!CRM.Designer) CRM.Designer = {}; | |
3 | ||
4 | /** | |
5 | * When rendering a template with Marionette.ItemView, the list of variables is determined by | |
6 | * serializeData(). The normal behavior is to map each property of this.model to a template | |
7 | * variable. | |
8 | * | |
9 | * This function extends that practice by exporting variables "_view", "_model", "_collection", | |
10 | * and "_options". This makes it easier for the template to, e.g., access computed properties of | |
11 | * a model (by calling "_model.getComputedProperty"), or to access constructor options (by | |
12 | * calling "_options.myoption"). | |
13 | * | |
14 | * @return {*} | |
15 | */ | |
16 | var extendedSerializeData = function() { | |
17 | var result = Marionette.ItemView.prototype.serializeData.apply(this); | |
18 | result._view = this; | |
19 | result._model = this.model; | |
20 | result._collection = this.collection; | |
21 | result._options = this.options; | |
22 | return result; | |
23 | } | |
24 | ||
25 | /** | |
26 | * Display a dialog window with an editable form for a UFGroupModel | |
27 | * | |
28 | * The implementation here is very "jQuery-style" and not "Backbone-style"; | |
29 | * it's been extracted | |
30 | * | |
31 | * options: | |
32 | * - model: CRM.UF.UFGroupModel | |
33 | */ | |
34 | CRM.Designer.DesignerDialog = Backbone.Marionette.Layout.extend({ | |
35 | serializeData: extendedSerializeData, | |
36 | template: '#designer_dialog_template', | |
37 | className: 'crm-designer-dialog', | |
38 | regions: { | |
39 | designerRegion: '.crm-designer' | |
40 | }, | |
41 | /** @var bool whether this dialog is currently open */ | |
42 | isDialogOpen: false, | |
43 | /** @var bool whether any changes have been made */ | |
44 | isUfUnsaved: false, | |
45 | /** @var obj handle for the CRM.alert containing undo link */ | |
46 | undoAlert: null, | |
47 | /** @var bool whether this dialog is being re-opened by the undo link */ | |
48 | undoState: false, | |
49 | ||
50 | initialize: function(options) { | |
51 | CRM.designerApp.vent.on('ufUnsaved', this.onUfChanged, this); | |
52 | }, | |
53 | onClose: function() { | |
54 | this.undoAlert && this.undoAlert.close && this.undoAlert.close(); | |
55 | CRM.designerApp.vent.off('ufUnsaved', this.onUfChanged, this); | |
56 | }, | |
57 | onUfChanged: function(isUfUnsaved) { | |
58 | this.isUfUnsaved = isUfUnsaved; | |
59 | }, | |
60 | onRender: function() { | |
61 | var designerDialog = this; | |
62 | designerDialog.$el.dialog({ | |
63 | autoOpen: true, // note: affects accordion height | |
64 | title: 'Edit Profile', | |
65 | width: '75%', | |
66 | height: 600, | |
67 | minWidth: 500, | |
68 | minHeight: 600, // to allow dropping in big whitespace, coordinate with min-height of .crm-designer-fields | |
69 | open: function() { | |
70 | // Prevent conflicts with other onbeforeunload handlers | |
71 | designerDialog.oldOnBeforeUnload = window.onbeforeunload; | |
72 | // Warn of unsaved changes when navigating away from the page | |
73 | window.onbeforeunload = function() { | |
74 | if (designerDialog.isDialogOpen && designerDialog.isUfUnsaved) { | |
75 | return ts("Your profile has not been saved."); | |
76 | } | |
77 | if (designerDialog.oldOnBeforeUnload) { | |
78 | return designerDialog.oldOnBeforeUnload.apply(arguments); | |
79 | } | |
80 | }; | |
81 | designerDialog.undoAlert && designerDialog.undoAlert.close && designerDialog.undoAlert.close(); | |
82 | designerDialog.isDialogOpen = true; | |
83 | // Initialize new dialog if we are not re-opening unsaved changes | |
84 | if (designerDialog.undoState === false) { | |
85 | designerDialog.designerRegion && designerDialog.designerRegion.close && designerDialog.designerRegion.close(); | |
86 | designerDialog.$el.block({message: 'Loading...', theme: true}); | |
87 | designerDialog.options.findCreateUfGroupModel({ | |
88 | onLoad: function(ufGroupModel) { | |
89 | designerDialog.model = ufGroupModel; | |
90 | var designerLayout = new CRM.Designer.DesignerLayout({ | |
91 | model: ufGroupModel, | |
92 | el: '<div class="full-height"></div>' | |
93 | }); | |
94 | designerDialog.$el.unblock(); | |
95 | designerDialog.designerRegion.show(designerLayout); | |
96 | CRM.designerApp.vent.trigger('resize'); | |
97 | designerDialog.isUfUnsaved = false; | |
98 | } | |
99 | }); | |
100 | } | |
101 | designerDialog.undoState = false; | |
102 | }, | |
103 | close: function() { | |
104 | window.onbeforeunload = designerDialog.oldOnBeforeUnload; | |
105 | designerDialog.isDialogOpen = false; | |
106 | ||
107 | designerDialog.undoAlert && designerDialog.undoAlert.close && designerDialog.undoAlert.close(); | |
108 | if (designerDialog.isUfUnsaved) { | |
109 | designerDialog.undoAlert = CRM.alert('<p>' + ts('Your changes to "%1" have not been saved.', {1: designerDialog.model.get('title')}) + '</p><a href="#" class="crm-undo">' + ts('Restore unsaved changes') + '</a>', ts('Unsaved Changes'), 'alert', {expires: 60000}); | |
110 | $('.ui-notify-message a.crm-undo').click(function() { | |
111 | designerDialog.undoState = true; | |
112 | designerDialog.$el.dialog('open'); | |
113 | return false; | |
114 | }); | |
115 | } | |
116 | }, | |
117 | resize: function() { | |
118 | CRM.designerApp.vent.trigger('resize'); | |
119 | } | |
120 | }); | |
121 | } | |
122 | }); | |
123 | ||
124 | /** | |
125 | * Display a complete form-editing UI, including canvas, palette, and | |
126 | * buttons. | |
127 | * | |
128 | * options: | |
129 | * - model: CRM.UF.UFGroupModel | |
130 | */ | |
131 | CRM.Designer.DesignerLayout = Backbone.Marionette.Layout.extend({ | |
132 | serializeData: extendedSerializeData, | |
133 | template: '#designer_template', | |
134 | regions: { | |
135 | buttons: '.crm-designer-buttonset-region', | |
136 | palette: '.crm-designer-palette-region', | |
137 | form: '.crm-designer-form-region', | |
138 | fields: '.crm-designer-fields-region' | |
139 | }, | |
140 | initialize: function() { | |
141 | CRM.designerApp.vent.on('resize', this.onResize, this); | |
142 | }, | |
143 | onClose: function() { | |
144 | CRM.designerApp.vent.off('resize', this.onResize, this); | |
145 | }, | |
146 | onRender: function() { | |
147 | this.buttons.show(new CRM.Designer.ToolbarView({ | |
148 | model: this.model | |
149 | })); | |
150 | this.palette.show(new CRM.Designer.PaletteView({ | |
151 | model: this.model | |
152 | })); | |
153 | this.form.show(new CRM.Designer.UFGroupView({ | |
154 | model: this.model | |
155 | })); | |
156 | this.fields.show(new CRM.Designer.UFFieldCanvasView({ | |
157 | model: this.model | |
158 | })); | |
159 | }, | |
160 | onResize: function() { | |
161 | if (! this.hasResizedBefore) { | |
162 | this.hasResizedBefore = true; | |
163 | this.$('.crm-designer-toolbar').resizable({ | |
164 | handles: 'w', | |
165 | maxWidth: 400, | |
166 | minWidth: 150, | |
167 | resize: function(event, ui) { | |
168 | $('.crm-designer-canvas').css('margin-right', (ui.size.width + 10) + 'px'); | |
169 | $(this).css({left: '', height: ''}); | |
170 | } | |
171 | }).css({left: '', height: ''}); | |
172 | } | |
173 | } | |
174 | }); | |
175 | ||
176 | /** | |
177 | * Display toolbar with working button | |
178 | * | |
179 | * options: | |
180 | * - model: CRM.UF.UFGroupModel | |
181 | */ | |
182 | CRM.Designer.ToolbarView = Backbone.Marionette.ItemView.extend({ | |
183 | serializeData: extendedSerializeData, | |
184 | template: '#designer_buttons_template', | |
185 | previewMode: false, | |
186 | events: { | |
187 | 'click .crm-designer-save': 'doSave', | |
188 | 'click .crm-designer-preview': 'doPreview' | |
189 | }, | |
190 | onRender: function() { | |
191 | this.$('.crm-designer-save').button(); | |
192 | this.$('.crm-designer-preview').button(); | |
193 | }, | |
194 | doSave: function(event) { | |
195 | var ufGroupModel = this.model; | |
196 | if (ufGroupModel.getRel('ufFieldCollection').hasDuplicates()) { | |
197 | CRM.alert(ts('Please correct errors before saving.'), '', 'alert'); | |
198 | return; | |
199 | } | |
200 | var $dialog = this.$el.closest('.crm-designer-dialog'); // FIXME use events | |
201 | $dialog.block({message: 'Saving...', theme: true}); | |
202 | var profile = ufGroupModel.toStrictJSON(); | |
203 | profile["api.UFField.replace"] = {values: ufGroupModel.getRel('ufFieldCollection').toSortedJSON(), 'option.autoweight': 0}; | |
204 | CRM.api('UFGroup', 'create', profile, { | |
205 | success: function(data) { | |
206 | $dialog.unblock(); | |
207 | var error = false; | |
208 | if (data.is_error) { | |
209 | CRM.alert(data.error_message); | |
210 | error = true; | |
211 | } | |
212 | _.each(data.values, function(ufGroupResponse) { | |
213 | if (ufGroupResponse['api.UFField.replace'].is_error) { | |
214 | CRM.alert(ufGroupResponse['api.UFField.replace'].error_message); | |
215 | error = true; | |
216 | } | |
217 | }); | |
218 | if (!error) { | |
219 | if (!ufGroupModel.get('id')) { | |
220 | ufGroupModel.set('id', data.id); | |
221 | } | |
222 | CRM.designerApp.vent.trigger('ufUnsaved', false); | |
223 | CRM.designerApp.vent.trigger('ufSaved'); | |
224 | $dialog.dialog('close'); | |
225 | } | |
226 | } | |
227 | }); | |
228 | return false; | |
229 | }, | |
230 | doPreview: function(event) { | |
231 | this.previewMode = !this.previewMode; | |
232 | if (!this.previewMode) { | |
233 | $('.crm-designer-preview-canvas').html(''); | |
234 | $('.crm-designer-canvas > *, .crm-designer-palette-region').show(); | |
235 | $('.crm-designer-preview span').html(ts('Preview')); | |
236 | return; | |
237 | } | |
238 | if (this.model.getRel('ufFieldCollection').hasDuplicates()) { | |
239 | CRM.alert(ts('Please correct errors before previewing.'), '', 'alert'); | |
240 | return; | |
241 | } | |
242 | var $dialog = this.$el.closest('.crm-designer-dialog'); // FIXME use events | |
243 | $dialog.block({message: 'Loading...', theme: true}); | |
244 | $.ajax({ | |
245 | url: CRM.url("civicrm/ajax/inline"), | |
246 | type: 'POST', | |
247 | data: { | |
248 | 'qfKey': CRM.profilePreviewKey, | |
249 | 'class_name': 'CRM_UF_Form_Inline_Preview', | |
250 | 'snippet': 1, | |
251 | 'ufData': JSON.stringify({ | |
252 | ufGroup: this.model.toStrictJSON(), | |
253 | ufFieldCollection: this.model.getRel('ufFieldCollection').toSortedJSON() | |
254 | }) | |
255 | } | |
256 | }).done(function(data) { | |
257 | $dialog.unblock(); | |
258 | $('.crm-designer-canvas > *, .crm-designer-palette-region').hide(); | |
259 | $('.crm-designer-preview-canvas').html(data).show(); | |
260 | $('.crm-designer-preview span').html(ts('Edit')); | |
261 | }); | |
262 | return false; | |
263 | } | |
264 | }); | |
265 | ||
266 | /** | |
267 | * Display a selection of available fields | |
268 | * | |
269 | * options: | |
270 | * - model: CRM.UF.UFGroupModel | |
271 | */ | |
272 | CRM.Designer.PaletteView = Backbone.Marionette.ItemView.extend({ | |
273 | serializeData: extendedSerializeData, | |
274 | template: '#palette_template', | |
275 | el: '<div class="full-height"></div>', | |
276 | events: { | |
277 | 'keyup .crm-designer-palette-search input': 'doSearch', | |
278 | 'click .crm-designer-palette-clear-search': 'clearSearch', | |
279 | 'click .crm-designer-palette-refresh': 'doRefresh', | |
280 | 'click .crm-designer-palette-toggle': 'toggleAll' | |
281 | }, | |
282 | initialize: function() { | |
283 | this.model.getRel('ufFieldCollection') | |
284 | .on('add', this.toggleActive, this) | |
285 | .on('remove', this.toggleActive, this); | |
286 | this.model.getRel('paletteFieldCollection') | |
287 | .on('reset', this.render, this); | |
288 | CRM.designerApp.vent.on('resize', this.onResize, this); | |
289 | }, | |
290 | onClose: function() { | |
291 | this.model.getRel('ufFieldCollection') | |
292 | .off('add', this.toggleActive, this) | |
293 | .off('remove', this.toggleActive, this); | |
294 | this.model.getRel('paletteFieldCollection') | |
295 | .off('reset', this.render, this); | |
296 | CRM.designerApp.vent.off('resize', this.onResize, this); | |
297 | }, | |
298 | onRender: function() { | |
299 | var paletteView = this; | |
300 | ||
301 | // Prepare data for jstree | |
302 | var treeData = []; | |
303 | var paletteFieldsByEntitySection = this.model.getRel('paletteFieldCollection').getFieldsByEntitySection(); | |
304 | ||
305 | paletteView.model.getRel('ufEntityCollection').each(function(ufEntityModel){ | |
306 | _.each(ufEntityModel.getSections(), function(section, sectionKey){ | |
307 | var entitySection = ufEntityModel.get('entity_name') + '-' + sectionKey; | |
308 | var items = []; | |
309 | if (paletteFieldsByEntitySection[entitySection]) { | |
310 | _.each(paletteFieldsByEntitySection[entitySection], function(paletteFieldModel, k) { | |
311 | items.push({data: paletteFieldModel.getLabel(), attr: {'class': 'crm-designer-palette-field', 'data-plm-cid': paletteFieldModel.cid}}); | |
312 | }); | |
313 | } | |
314 | if (section.is_addable) { | |
315 | items.push({data: 'placeholder', attr: {'class': 'crm-designer-palette-add', 'data-entity': ufEntityModel.get('entity_name'), 'data-section': sectionKey}}); | |
316 | } | |
317 | if (items.length > 0) { | |
318 | treeData.push({data: section.title, children: items}); | |
319 | } | |
320 | }) | |
321 | }); | |
322 | ||
323 | this.$('.crm-designer-palette-tree').jstree({ | |
324 | 'json_data': {data: treeData}, | |
325 | 'search': { | |
326 | 'case_insensitive' : true, | |
327 | 'show_only_matches': true | |
328 | }, | |
329 | themes: { | |
330 | "theme": 'classic', | |
331 | "dots": false, | |
332 | "icons": false | |
333 | }, | |
334 | 'plugins': ['themes', 'json_data', 'ui', 'search'] | |
335 | }).bind('loaded.jstree', function () { | |
336 | $('.crm-designer-palette-field', this).draggable({ | |
337 | appendTo: '.crm-designer', | |
338 | zIndex: $(this.$el).zIndex() + 5000, | |
339 | helper: 'clone', | |
340 | connectToSortable: '.crm-designer-fields' // FIXME: tight canvas/palette coupling | |
341 | }); | |
342 | $('.crm-designer-palette-field', this).dblclick(function(event){ | |
343 | var paletteFieldModel = paletteView.model.getRel('paletteFieldCollection').get($(event.currentTarget).attr('data-plm-cid')); | |
344 | paletteFieldModel.addToUFCollection(paletteView.model.getRel('ufFieldCollection')); | |
345 | event.stopPropagation(); | |
346 | }); | |
347 | paletteView.model.getRel('ufFieldCollection').each(function(ufFieldModel) { | |
348 | paletteView.toggleActive(ufFieldModel, paletteView.model.getRel('ufFieldCollection')) | |
349 | }); | |
350 | paletteView.$('.crm-designer-palette-add a').remove(); | |
351 | paletteView.$('.crm-designer-palette-add').append('<button>'+ts('Add Field')+'</button>'); | |
352 | paletteView.$('.crm-designer-palette-add button').button() | |
353 | .click(function(event){ | |
354 | var entityKey = $(event.currentTarget).closest('.crm-designer-palette-add').attr('data-entity'); | |
355 | var sectionKey = $(event.currentTarget).closest('.crm-designer-palette-add').attr('data-section'); | |
356 | var ufEntityModel = paletteView.model.getRel('ufEntityCollection').getByName(entityKey); | |
357 | var sections = ufEntityModel.getSections(); | |
358 | paletteView.doAddField(sections[sectionKey]); | |
359 | event.stopPropagation(); | |
360 | }) | |
361 | ; | |
362 | }).bind("select_node.jstree", function (e, data) { | |
363 | $(this).jstree("toggle_node", data.rslt.obj); | |
364 | $(this).jstree("deselect_node", data.rslt.obj); | |
365 | }); | |
366 | ||
367 | // FIXME: tight canvas/palette coupling | |
368 | this.$(".crm-designer-fields").droppable({ | |
369 | activeClass: "ui-state-default", | |
370 | hoverClass: "ui-state-hover", | |
371 | accept: ":not(.ui-sortable-helper)" | |
372 | }); | |
373 | ||
374 | this.onResize(); | |
375 | }, | |
376 | onResize: function() { | |
377 | var pos = this.$('.crm-designer-palette-tree').position(); | |
378 | var div = this.$('.crm-designer-palette-tree').closest('.crm-container').height(); | |
379 | this.$('.crm-designer-palette-tree').css({height: div - pos.top}); | |
380 | }, | |
381 | doSearch: function(event) { | |
382 | $('.crm-designer-palette-tree').jstree("search", $(event.target).val()); | |
383 | }, | |
384 | doAddField: function(section) { | |
385 | var paletteView = this; | |
386 | var openAddNewWindow = function() { | |
387 | var url = CRM.url('civicrm/admin/custom/group/field/add', { | |
388 | reset: 1, | |
389 | action: 'add', | |
390 | gid: section.custom_group_id | |
391 | }); | |
392 | window.open(url, '_blank'); | |
393 | }; | |
394 | ||
395 | if (paletteView.hideAddFieldAlert) { | |
396 | openAddNewWindow(); | |
397 | } else { | |
398 | CRM.confirm({ | |
399 | title: ts('Add Field'), | |
400 | message: ts('A new window or tab will open. Use the new window to add your field, and then return to this window and click "Refresh."'), | |
401 | onContinue: function() { | |
402 | paletteView.hideAddFieldAlert = true; | |
403 | openAddNewWindow(); | |
404 | } | |
405 | }); | |
406 | } | |
407 | return false; | |
408 | }, | |
409 | doRefresh: function(event) { | |
410 | var ufGroupModel = this.model; | |
411 | CRM.Schema.reloadModels() | |
412 | .done(function(data){ | |
413 | ufGroupModel.resetEntities(); | |
414 | }) | |
415 | .fail(function() { | |
416 | CRM.alert(ts('Failed to retrieve schema'), ts('Error'), 'error'); | |
417 | }); | |
418 | return false; | |
419 | }, | |
420 | clearSearch: function(event) { | |
421 | $('.crm-designer-palette-search input').val('').keyup(); | |
422 | return false; | |
423 | }, | |
424 | toggleActive: function(ufFieldModel, ufFieldCollection, options) { | |
425 | var paletteFieldCollection = this.model.getRel('paletteFieldCollection'); | |
426 | var paletteFieldModel = paletteFieldCollection.getFieldByName(ufFieldModel.get('entity_name'), ufFieldModel.get('field_name')); | |
427 | var isAddable = ufFieldCollection.isAddable(ufFieldModel); | |
428 | this.$('[data-plm-cid='+paletteFieldModel.cid+']').toggleClass('disabled', !isAddable); | |
429 | }, | |
430 | toggleAll: function(event) { | |
431 | if ($('.crm-designer-palette-search input').val() == '') { | |
432 | $('.crm-designer-palette-tree').jstree($(event.target).attr('rel')); | |
433 | } | |
434 | return false; | |
435 | } | |
436 | }); | |
437 | ||
438 | /** | |
439 | * Display all UFFieldModel objects in a UFGroupModel. | |
440 | * | |
441 | * options: | |
442 | * - model: CRM.UF.UFGroupModel | |
443 | */ | |
444 | CRM.Designer.UFFieldCanvasView = Backbone.Marionette.View.extend({ | |
445 | initialize: function() { | |
446 | this.model.getRel('ufFieldCollection') | |
447 | .on('add', this.updatePlaceholder, this) | |
448 | .on('remove', this.updatePlaceholder, this) | |
449 | .on('add', this.addUFFieldView, this); | |
450 | }, | |
451 | onClose: function() { | |
452 | this.model.getRel('ufFieldCollection') | |
453 | .off('add', this.updatePlaceholder, this) | |
454 | .off('remove', this.updatePlaceholder, this) | |
455 | .off('add', this.addUFFieldView, this); | |
456 | }, | |
457 | render: function() { | |
458 | var ufFieldCanvasView = this; | |
459 | this.$el.html(_.template($('#field_canvas_view_template').html())); | |
460 | ||
461 | // BOTTOM: Setup field-level editing | |
462 | var $fields = this.$('.crm-designer-fields'); | |
463 | this.updatePlaceholder(); | |
464 | var ufFieldModels = this.model.getRel('ufFieldCollection').sortBy(function(ufFieldModel) { | |
465 | return parseInt(ufFieldModel.get('weight')); | |
466 | }); | |
467 | _.each(ufFieldModels, function(ufFieldModel) { | |
468 | ufFieldCanvasView.addUFFieldView(ufFieldModel, ufFieldCanvasView.model.getRel('ufFieldCollection'), {skipWeights: true}); | |
469 | }); | |
470 | this.$(".crm-designer-fields").sortable({ | |
471 | placeholder: 'crm-designer-row-placeholder', | |
472 | forcePlaceholderSize: true, | |
473 | receive: function(event, ui) { | |
474 | var paletteFieldModel = ufFieldCanvasView.model.getRel('paletteFieldCollection').get(ui.item.attr('data-plm-cid')); | |
475 | var ufFieldModel = paletteFieldModel.addToUFCollection( | |
476 | ufFieldCanvasView.model.getRel('ufFieldCollection'), | |
477 | {skipWeights: true} | |
478 | ); | |
479 | if (null == ufFieldModel) { | |
480 | ufFieldCanvasView.$('.crm-designer-fields .ui-draggable').remove(); | |
481 | } else { | |
482 | // Move from end to the 'dropped' position | |
483 | var ufFieldViewEl = ufFieldCanvasView.$('div[data-field-cid='+ufFieldModel.cid+']').parent(); | |
484 | ufFieldCanvasView.$('.crm-designer-fields .ui-draggable').replaceWith(ufFieldViewEl); | |
485 | } | |
486 | // note: the sortable() update callback will call updateWeight | |
487 | }, | |
488 | update: function() { | |
489 | ufFieldCanvasView.updateWeights(); | |
490 | } | |
491 | }); | |
492 | }, | |
493 | /** Determine visual order of fields and set the model values for "weight" */ | |
494 | updateWeights: function() { | |
495 | var ufFieldCanvasView = this; | |
496 | var weight = 1; | |
497 | var rows = this.$('.crm-designer-row').each(function(key, row) { | |
498 | if ($(row).hasClass('placeholder')) { | |
499 | return; | |
500 | } | |
501 | var ufFieldCid = $(row).attr('data-field-cid'); | |
502 | var ufFieldModel = ufFieldCanvasView.model.getRel('ufFieldCollection').get(ufFieldCid); | |
503 | ufFieldModel.set('weight', weight); | |
504 | weight++; | |
505 | }); | |
506 | }, | |
507 | addUFFieldView: function(ufFieldModel, ufFieldCollection, options) { | |
508 | var paletteFieldModel = this.model.getRel('paletteFieldCollection').getFieldByName(ufFieldModel.get('entity_name'), ufFieldModel.get('field_name')); | |
509 | var ufFieldView = new CRM.Designer.UFFieldView({ | |
510 | el: $("<div></div>"), | |
511 | model: ufFieldModel, | |
512 | paletteFieldModel: paletteFieldModel | |
513 | }); | |
514 | ufFieldView.render(); | |
515 | this.$('.crm-designer-fields').append(ufFieldView.$el); | |
516 | if (! (options && options.skipWeights)) { | |
517 | this.updateWeights(); | |
518 | } | |
519 | }, | |
520 | updatePlaceholder: function() { | |
521 | if (this.model.getRel('ufFieldCollection').isEmpty()) { | |
522 | this.$('.placeholder').css({display: 'block', border: '0 none', cursor: 'default'}); | |
523 | } else { | |
524 | this.$('.placeholder').hide(); | |
525 | } | |
526 | } | |
527 | }); | |
528 | ||
529 | /** | |
530 | * options: | |
531 | * - model: CRM.UF.UFFieldModel | |
532 | * - paletteFieldModel: CRM.Designer.PaletteFieldModel | |
533 | */ | |
534 | CRM.Designer.UFFieldView = Backbone.Marionette.Layout.extend({ | |
535 | serializeData: extendedSerializeData, | |
536 | template: '#field_row_template', | |
537 | expanded: false, | |
538 | regions: { | |
539 | summary: '.crm-designer-field-summary', | |
540 | detail: '.crm-designer-field-detail' | |
541 | }, | |
542 | events: { | |
543 | "click .crm-designer-action-settings": 'doToggleForm', | |
544 | "click .crm-designer-action-remove": 'doRemove' | |
545 | }, | |
546 | modelEvents: { | |
547 | "destroy": 'remove', | |
548 | "change:is_duplicate": 'onChangeIsDuplicate' | |
549 | }, | |
550 | onRender: function() { | |
551 | this.summary.show(new CRM.Designer.UFFieldSummaryView({ | |
552 | model: this.model, | |
553 | fieldSchema: this.model.getFieldSchema(), | |
554 | paletteFieldModel: this.options.paletteFieldModel | |
555 | })); | |
556 | this.detail.show(new CRM.Designer.UFFieldDetailView({ | |
557 | model: this.model, | |
558 | fieldSchema: this.model.getFieldSchema() | |
559 | })); | |
560 | this.onChangeIsDuplicate(this.model, this.model.get('is_duplicate')) | |
561 | if (!this.expanded) { | |
562 | this.detail.$el.hide(); | |
563 | } | |
564 | var that = this; | |
565 | CRM.designerApp.vent.on('formOpened', function(event) { | |
566 | if (that.expanded && event != that.cid) { | |
567 | that.doToggleForm(false); | |
568 | } | |
569 | }); | |
570 | }, | |
571 | doToggleForm: function(event) { | |
572 | this.expanded = !this.expanded; | |
573 | if (this.expanded && event !== false) { | |
574 | CRM.designerApp.vent.trigger('formOpened', this.cid); | |
575 | } | |
576 | this.$el.toggleClass('crm-designer-open', this.expanded); | |
577 | var $detail = this.detail.$el; | |
578 | if (!this.expanded) { | |
579 | $detail.toggle('blind', 250); | |
580 | } | |
581 | else { | |
582 | var $canvas = $('.crm-designer-canvas'); | |
583 | var top = $canvas.offset().top; | |
584 | $detail.slideDown({ | |
585 | duration: 250, | |
586 | step: function(num, effect) { | |
587 | // Scroll canvas to keep field details visible | |
588 | if (effect.prop == 'height') { | |
589 | if (effect.now + $detail.offset().top - top > $canvas.height() - 9) { | |
590 | $canvas.scrollTop($canvas.scrollTop() + effect.now + $detail.offset().top - top - $canvas.height() + 9); | |
591 | } | |
592 | } | |
593 | } | |
594 | }); | |
595 | } | |
596 | }, | |
597 | onChangeIsDuplicate: function(model, value, options) { | |
598 | this.$el.toggleClass('crm-designer-duplicate', value); | |
599 | }, | |
600 | doRemove: function(event) { | |
601 | var that = this; | |
602 | this.$el.hide(250, function() { | |
603 | that.model.destroyLocal(); | |
604 | }); | |
605 | } | |
606 | }); | |
607 | ||
608 | /** | |
609 | * options: | |
610 | * - model: CRM.UF.UFFieldModel | |
611 | * - fieldSchema: (Backbone.Form schema element) | |
612 | * - paletteFieldModel: CRM.Designer.PaletteFieldModel | |
613 | */ | |
614 | CRM.Designer.UFFieldSummaryView = Backbone.Marionette.ItemView.extend({ | |
615 | serializeData: extendedSerializeData, | |
616 | template: '#field_summary_template', | |
617 | modelEvents: { | |
618 | 'change': 'render' | |
619 | }, | |
620 | ||
621 | /** | |
622 | * Compose a printable string which describes the binding of this UFField to the data model | |
623 | * @return {String} | |
624 | */ | |
625 | getBindingLabel: function() { | |
626 | var result = this.options.paletteFieldModel.getSection().title + ": " + this.options.paletteFieldModel.getLabel(); | |
627 | if (this.options.fieldSchema.civiIsPhone) { | |
628 | result = result + '-' + CRM.PseudoConstant.phoneType[this.model.get('phone_type_id')]; | |
629 | } | |
630 | if (this.options.fieldSchema.civiIsLocation) { | |
631 | var locType = this.model.get('location_type_id') ? CRM.PseudoConstant.locationType[this.model.get('location_type_id')] : ts('Primary'); | |
632 | result = result + ' (' + locType + ')'; | |
633 | } | |
634 | return result; | |
635 | }, | |
636 | ||
637 | /** | |
638 | * Return a string marking if the field is required | |
639 | * @return {String} | |
640 | */ | |
641 | getRequiredMarker: function() { | |
642 | if (this.model.get('is_required') == 1) { | |
643 | return ' <span class="crm-marker">*</span> '; | |
644 | } | |
645 | return ''; | |
646 | }, | |
647 | ||
648 | onRender: function() { | |
649 | this.$el.toggleClass('disabled', this.model.get('is_active') != 1); | |
650 | if (this.model.get("is_reserved") == 1) { | |
651 | this.$('.crm-designer-buttons').hide(); | |
652 | } | |
653 | } | |
654 | }); | |
655 | ||
656 | /** | |
657 | * options: | |
658 | * - model: CRM.UF.UFFieldModel | |
659 | * - fieldSchema: (Backbone.Form schema element) | |
660 | */ | |
661 | CRM.Designer.UFFieldDetailView = Backbone.View.extend({ | |
662 | initialize: function() { | |
663 | // FIXME: hide/display 'in_selector' if 'visibility' is one of the public options | |
664 | var fields = ['location_type_id', 'phone_type_id', 'label', 'is_multi_summary', 'is_required', 'is_view', 'visibility', 'in_selector', 'is_searchable', 'help_pre', 'help_post', 'is_active']; | |
665 | if (! this.options.fieldSchema.civiIsLocation) { | |
666 | fields = _.without(fields, 'location_type_id'); | |
667 | } | |
668 | if (! this.options.fieldSchema.civiIsPhone) { | |
669 | fields = _.without(fields, 'phone_type_id'); | |
670 | } | |
671 | if (!this.options.fieldSchema.civiIsMultiple) { | |
672 | fields = _.without(fields, 'is_multi_summary'); | |
673 | } | |
674 | ||
675 | this.form = new Backbone.Form({ | |
676 | model: this.model, | |
677 | fields: fields | |
678 | }); | |
679 | this.form.on('change', this.onFormChange, this); | |
680 | }, | |
681 | render: function() { | |
682 | this.$el.html(this.form.render().el); | |
683 | this.onFormChange(); | |
684 | }, | |
685 | onFormChange: function() { | |
686 | this.form.commit(); | |
687 | this.$('.field-is_multi_summary').toggle(this.options.fieldSchema.civiIsMultiple ? true : false); | |
688 | this.$('.field-in_selector').toggle(this.model.isInSelectorAllowed()); | |
689 | // this.$(':input').attr('disabled', this.model.get("is_reserved") == 1); | |
690 | ||
691 | if (!this.model.isInSelectorAllowed() && this.model.get('in_selector') != "0") { | |
692 | this.model.set('in_selector', "0"); | |
693 | this.form.setValue('in_selector', "0"); | |
694 | // TODO: It might be nicer if we didn't completely discard in_selector -- e.g. | |
695 | // if the value could be restored when the user isInSelectorAllowed becomes true | |
696 | // again. However, I haven't found a simple way to do this. | |
697 | } | |
698 | } | |
699 | }); | |
700 | ||
701 | /** | |
702 | * options: | |
703 | * - model: CRM.UF.UFGroupModel | |
704 | */ | |
705 | CRM.Designer.UFGroupView = Backbone.Marionette.Layout.extend({ | |
706 | serializeData: extendedSerializeData, | |
707 | template: '#form_row_template', | |
708 | expanded: false, | |
709 | regions: { | |
710 | summary: '.crm-designer-form-summary', | |
711 | detail: '.crm-designer-form-detail' | |
712 | }, | |
713 | events: { | |
714 | "click .crm-designer-action-settings": 'doToggleForm' | |
715 | }, | |
716 | onRender: function() { | |
717 | this.summary.show(new CRM.Designer.UFGroupSummaryView({ | |
718 | model: this.model | |
719 | })); | |
720 | this.detail.show(new CRM.Designer.UFGroupDetailView({ | |
721 | model: this.model | |
722 | })); | |
723 | if (!this.expanded) { | |
724 | this.detail.$el.hide(); | |
725 | } | |
726 | var that = this; | |
727 | CRM.designerApp.vent.on('formOpened', function(event) { | |
728 | if (that.expanded && event !== 0) { | |
729 | that.doToggleForm(false); | |
730 | } | |
731 | }); | |
732 | }, | |
733 | doToggleForm: function(event) { | |
734 | this.expanded = !this.expanded; | |
735 | if (this.expanded && event !== false) { | |
736 | CRM.designerApp.vent.trigger('formOpened', 0); | |
737 | } | |
738 | this.$el.toggleClass('crm-designer-open', this.expanded); | |
739 | this.detail.$el.toggle('blind', 250); | |
740 | } | |
741 | }); | |
742 | ||
743 | /** | |
744 | * options: | |
745 | * - model: CRM.UF.UFGroupModel | |
746 | */ | |
747 | CRM.Designer.UFGroupSummaryView = Backbone.Marionette.ItemView.extend({ | |
748 | serializeData: extendedSerializeData, | |
749 | template: '#form_summary_template', | |
750 | modelEvents: { | |
751 | 'change': 'render' | |
752 | }, | |
753 | onRender: function() { | |
754 | this.$el.toggleClass('disabled', this.model.get('is_active') != 1); | |
755 | if (this.model.get("is_reserved") == 1) { | |
756 | this.$('.crm-designer-buttons').hide(); | |
757 | } | |
758 | } | |
759 | }); | |
760 | ||
761 | /** | |
762 | * options: | |
763 | * - model: CRM.UF.UFGroupModel | |
764 | */ | |
765 | CRM.Designer.UFGroupDetailView = Backbone.View.extend({ | |
766 | initialize: function() { | |
767 | this.form = new Backbone.Form({ | |
768 | model: this.model, | |
769 | fields: ['title', 'help_pre', 'help_post', 'is_active'] | |
770 | }); | |
771 | this.form.on('change', this.form.commit, this.form); | |
772 | }, | |
773 | render: function() { | |
774 | this.$el.html(this.form.render().el); | |
775 | } | |
776 | }); | |
777 | ||
778 | })(cj); |