Completed
Pull Request — develop (#161)
by Wachter
22:54 queued 09:56
created

main.js ➔ ... ➔ .renderFormTemplate   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 27
rs 8.439
cc 5
nc 5
nop 1
1
/*
2
 * This file is part of Sulu.
3
 *
4
 * (c) MASSIVE ART WebServices GmbH
5
 *
6
 * This source file is subject to the MIT license that is bundled
7
 * with this source code in the file LICENSE.
8
 */
9
10
define([
11
    'underscore',
12
    'jquery',
13
    'services/suluarticle/article-manager',
14
    'services/suluarticle/article-router',
15
    'services/suluarticle/property-configuration'
16
], function(_, $, ArticleManager, ArticleRouter, PropertyConfiguration) {
17
18
    'use strict';
19
20
    return {
21
22
        layout: function() {
23
            return {
24
                extendExisting: true,
25
26
                content: {
27
                    width: (!!this.options.preview) ? 'fixed' : 'max',
28
                    rightSpace: false,
29
                    leftSpace: false
30
                }
31
            };
32
        },
33
34
        initialize: function() {
35
            this.saved = true;
36
37
            this.render();
38
39
            this.bindCustomEvents();
40
            this.listenForChange();
41
        },
42
43
        bindCustomEvents: function() {
44
            this.sandbox.on('sulu.tab.template-change', function(item) {
45
                this.checkRenderTemplate(item.template);
46
            }, this);
47
48
            this.sandbox.on('sulu.content.contents.default-template', function(name) {
49
                this.template = name;
50
                this.sandbox.emit('sulu.header.toolbar.item.change', 'template', name);
51
            }.bind(this));
52
53
            this.sandbox.on('sulu.tab.save', this.save.bind(this));
54
        },
55
56
        listenForChange: function() {
57
            this.sandbox.dom.on(this.$el, 'keyup', _.debounce(this.setDirty.bind(this), 10), 'input, textarea');
58
            this.sandbox.dom.on(this.$el, 'change', _.debounce(this.setDirty.bind(this), 10), 'input[type="checkbox"], select');
59
            this.sandbox.on('sulu.content.changed', this.setDirty.bind(this));
60
        },
61
62
        setDirty: function() {
63
            this.saved = false;
64
            this.sandbox.emit('sulu.tab.dirty');
65
        },
66
67
        /**
68
         * @param {Object} action
69
         */
70
        save: function(action) {
71
            if (!this.sandbox.form.validate(this.formId)) {
72
                this.sandbox.emit('sulu.tab.dirty', true);
73
74
                return;
75
            }
76
77
            var data = this.sandbox.form.getData(this.formId);
78
            this.options.adapter.save(this, data, action).done(function(response) {
79
                this.data = response;
80
81
                if (this.ghost && !this.data.type) {
82
                    // reload page
83
                    return this.sandbox.emit(
84
                        'sulu.router.navigate',
85
                        this.sandbox.mvc.history.fragment,
86
                        true,
87
                        true
88
                    );
89
                }
90
91
                this.sandbox.emit('sulu.tab.saved', response.id, response);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
92
            }.bind(this)).fail(function(xhr) {
93
                this.sandbox.emit('sulu.article.error', xhr.status, data);
94
            }.bind(this));
95
        },
96
97
        render: function() {
98
            this.checkRenderTemplate(this.data.template || null);
99
        },
100
101
        /**
102
         * @param {String} template
103
         */
104
        checkRenderTemplate: function(template) {
105
            if (!!template && this.template === template) {
106
                return this.sandbox.emit('sulu.header.toolbar.item.enable', 'template', false);
107
            }
108
109
            this.sandbox.emit('sulu.header.toolbar.item.loading', 'template');
110
111
            if (this.template !== '' && !this.saved) {
112
                this.showRenderTemplateDialog(template);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
113
            } else {
114
                this.loadFormTemplate(template);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
115
            }
116
        },
117
118
        /**
119
         * @param {String} template
120
         */
121
        showRenderTemplateDialog: function(template) {
122
            // show warning dialog
123
            this.sandbox.emit('sulu.overlay.show-warning',
124
                'sulu.overlay.be-careful',
125
                'content.template.dialog.content',
126
                function() {
127
                    // cancel callback
128
                    this.sandbox.emit('sulu.header.toolbar.item.enable', 'template', false);
129
130
                    if (!!this.template) {
131
                        this.sandbox.emit('sulu.header.toolbar.item.change', 'template', this.template, false);
132
                    }
133
                }.bind(this),
134
                function() {
135
                    // ok callback
136
                    this.loadFormTemplate(template);
137
                }.bind(this)
138
            );
139
        },
140
141
        /**
142
         * @param {String} template
143
         */
144
        loadFormTemplate: function(template) {
145
            if (!template) {
146
                template = this.options.config.types[(this.options.type || this.data.articleType)].default;
147
            }
148
149
            this.template = template;
150
            this.formId = '#content-form-container';
151
            this.$container = this.sandbox.dom.createElement('<div id="content-form-container"/>');
152
            this.html(this.$container);
153
154
            if (!!this.sandbox.form.getObject(this.formId)) {
155
                var data = this.data;
156
                this.data = this.sandbox.form.getData(this.formId);
157
                if (!!data.id) {
158
                    this.data.id = data.id;
159
                }
160
161
                this.data = this.sandbox.util.extend({}, data, this.data);
162
            }
163
164
            require([this.getTemplateUrl(template)], this.renderFormTemplate.bind(this));
165
        },
166
167
        /**
168
         * @param {String} template
169
         *
170
         * @returns {String}
171
         */
172
        getTemplateUrl: function(template) {
173
            var url = 'text!/admin/content/template/form';
174
            if (!!template) {
175
                url += '/' + template + '.html';
176
            } else {
177
                url += '.html';
178
            }
179
            url += '?type=article&language=' + this.options.locale;
180
181
            if (!!this.data.id) {
182
                url += '&uuid=' + this.data.id;
183
            }
184
185
            return url;
186
        },
187
188
        /**
189
         * @param {String} template
190
         */
191
        renderFormTemplate: function(template) {
192
            this.sandbox.dom.html(this.formId, this.sandbox.util.template(template, {
193
                translate: this.sandbox.translate,
194
                content: this.data,
195
                options: this.options,
196
                entityClass: 'Sulu\\Bundle\\ArticleBundle\\Document\\ArticleDocument',
197
                entityId: this.options.id
198
            }));
199
200
            var data = this.options.adapter.prepareData(this.data, this);
201
            if (data.type && data.type.name === 'ghost') {
202
                this.ghost = {
203
                    locale: data.type.value,
204
                    title: titleProperty ? data[titleProperty.name] : '',
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable titleProperty is declared in the current environment, consider using typeof titleProperty === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
205
                    pageTitle: pageTitleProperty ? data[pageTitleProperty.name] : ''
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable pageTitleProperty is declared in the current environment, consider using typeof pageTitleProperty === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
206
                };
207
208
                data = {
209
                    id: this.data.id,
210
                    articleType: this.data.articleType
211
                };
212
            }
213
214
            this.options.adapter.beforeFormCreate(this);
215
216
            this.createForm(data).then(this.changeTemplateDropdownHandler.bind(this));
217
        },
218
219
        changeTemplateDropdownHandler: function() {
220
            if (!!this.template) {
221
                this.sandbox.emit('sulu.header.toolbar.item.change', 'template', this.template);
222
            }
223
            this.sandbox.emit('sulu.header.toolbar.item.enable', 'template', false);
224
        },
225
226
        /**
227
         * @param {Object} data
228
         *
229
         * @returns {Object}
230
         */
231
        createForm: function(data) {
232
            var formObject = this.sandbox.form.create(this.formId),
233
                deferred = this.sandbox.data.deferred();
234
235
            formObject.initialized.then(function() {
236
                this.sandbox.form.setData(this.formId, data).then(function() {
237
                    if (!!this.ghost) {
238
                        var titleProperty = this.getTitleProperty(),
239
                            pageTitleProperty = this.getPageTitleProperty();
240
241
                        if (titleProperty) {
242
                            this.sandbox.dom.attr(titleProperty.$el, 'placeholder', this.ghost.locale + ': ' + this.ghost.title);
243
                        }
244
245
                        if (pageTitleProperty) {
246
                            this.sandbox.dom.attr(pageTitleProperty.$el, 'placeholder', this.ghost.locale + ': ' + this.ghost.pageTitle);
247
                        }
248
                    }
249
250
                    this.sandbox.start(this.$el, {reset: true}).then(function() {
251
                        this.initSortableBlock();
252
                        this.bindFormEvents();
253
                        deferred.resolve();
254
255
                        if (!!this.options.preview) {
256
                            this.options.preview.bindDomEvents(this.$el);
257
                            var data = this.options.adapter.prepareData(this.data, this);
258
                            data.template = this.template;
259
                            if (!!data.type && data.type.name === 'ghost') {
260
                                data = {id: data.id};
261
                            }
262
263
                            this.options.preview.updateContext(
264
                                {template: this.template},
265
                                this.options.adapter.prepareData(data, this)
266
                            );
267
                        }
268
                    }.bind(this));
269
                }.bind(this));
270
            }.bind(this));
271
272
            return deferred.promise();
273
        },
274
275
        initSortableBlock: function() {
276
            var $sortable = this.sandbox.dom.find('.sortable', this.$el),
277
                sortable;
278
279
            if (!!$sortable && $sortable.length > 0) {
280
                this.sandbox.dom.sortable($sortable, 'destroy');
281
                sortable = this.sandbox.dom.sortable($sortable, {
282
                    handle: '.move',
283
                    forcePlaceholderSize: true
284
                });
285
286
                // (un)bind event listener
287
                this.sandbox.dom.unbind(sortable, 'sortupdate');
288
289
                sortable.bind('sortupdate', function(event) {
290
                    // update preview
291
                    this.updatePreviewProperty(event.currentTarget, null);
292
293
                    this.sandbox.emit('sulu.content.changed');
294
                }.bind(this));
295
            }
296
        },
297
298
        bindFormEvents: function() {
299
            this.sandbox.dom.on(this.formId, 'form-remove', function(event, propertyName) {
300
                this.initSortableBlock();
301
                this.setDirty();
302
303
                // update preview
304
                this.updatePreviewProperty(event.currentTarget, propertyName);
305
            }.bind(this));
306
307
            this.sandbox.dom.on(this.formId, 'form-add', function(event, propertyName, data, index) {
308
                var $elements = this.sandbox.dom.children(this.$find('[data-mapper-property="' + propertyName + '"]')),
309
                    $element = (index !== undefined && $elements.length > index) ? $elements[index] : this.sandbox.dom.last($elements);
310
311
                // start new subcomponents
312
                this.sandbox.start($element);
313
314
                // enable save button
315
                this.setDirty();
316
317
                // reinit sorting
318
                this.initSortableBlock();
319
320
                // update preview
321
                this.updatePreviewProperty(event.currentTarget, propertyName);
322
            }.bind(this));
323
324
            this.sandbox.dom.on(this.formId, 'init-sortable', function(e) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
325
                // reinit sorting
326
                this.initSortableBlock();
327
            }.bind(this));
328
        },
329
330
        loadComponentData: function() {
331
            return this.options.data();
332
        },
333
334
        /**
335
         * @param {Object} target
336
         * @param {String} propertyName
337
         */
338
        updatePreviewProperty: function(target, propertyName) {
339
            if (!!this.options.preview) {
340
                var data = this.sandbox.form.getData(this.formId);
341
342
                if (!propertyName && !!target) {
343
                    propertyName = this.sandbox.dom.data(target, 'mapperProperty');
344
                }
345
346
                this.options.preview.updateProperty(propertyName, data[propertyName]);
347
            }
348
        },
349
350
        getTitleProperty: function() {
351
            if (!this.propertyConfiguration) {
352
                this.propertyConfiguration = PropertyConfiguration.generate(this.$el);
353
            }
354
355
            if (!!this.propertyConfiguration.tags['sulu_article.article_title']) {
356
                return this.propertyConfiguration.tags['sulu_article.article_title'].highestProperty;
357
            }
358
359
            return this.propertyConfiguration.title;
360
        },
361
362
        getPageTitleProperty: function() {
363
            if (!this.propertyConfiguration) {
364
                this.propertyConfiguration = PropertyConfiguration.generate(this.$el);
365
            }
366
367
            if (!!this.propertyConfiguration.tags['sulu_article.page_title']) {
368
                return this.propertyConfiguration.tags['sulu_article.page_title'].highestProperty;
369
            } else if (!!this.propertyConfiguration.pageTitle) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if !(!this.propertyConfiguration.pageTitle) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
370
                return this.propertyConfiguration.pageTitle;
371
            }
372
        },
373
374
        getRoutePathProperty: function() {
375
            if (!this.propertyConfiguration) {
376
                this.propertyConfiguration = PropertyConfiguration.generate(this.$el);
377
            }
378
379
            if (!!this.propertyConfiguration.tags['sulu_article.article_route']) {
380
                return this.propertyConfiguration.tags['sulu_article.article_route'].highestProperty;
381
            } else if (!!this.propertyConfiguration.routePath) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if !(!this.propertyConfiguration.routePath) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
382
                return this.propertyConfiguration.routePath;
383
            }
384
        }
385
    };
386
});
387