Completed
Pull Request — develop (#161)
by Wachter
14:20
created

main.js ➔ ... ➔ .renderFormTemplate   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
dl 0
loc 27
rs 8.439
c 1
b 0
f 1
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, textarea');
59
            this.sandbox.dom.on(this.$el, 'change', _.debounce(this.setDirty.bind(this), 10), 'input[type="checkbox"], select');
60
            this.sandbox.on('sulu.content.changed', this.setDirty.bind(this));
61
        },
62
63
        setDirty: function() {
64
            this.saved = false;
65
            this.sandbox.emit('sulu.tab.dirty');
66
        },
67
68
        /**
69
         * @param {Object} action
70
         */
71
        save: function(action) {
72
            if (!this.sandbox.form.validate(this.formId)) {
73
                this.sandbox.emit('sulu.tab.dirty', true);
74
75
                return;
76
            }
77
78
            var data = this.sandbox.form.getData(this.formId);
79
            this.options.adapter.save(this, data, action).done(function(response) {
80
                this.data = response;
81
82
                if (this.ghost && !this.data.type) {
83
                    // reload page
84
                    return this.sandbox.emit(
85
                        'sulu.router.navigate',
86
                        this.sandbox.mvc.history.fragment,
87
                        true,
88
                        true
89
                    );
90
                }
91
92
                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...
93
            }.bind(this)).fail(function(xhr) {
94
                this.sandbox.emit('sulu.article.error', xhr.status, data);
95
            }.bind(this));
96
        },
97
98
        render: function() {
99
            this.checkRenderTemplate(this.data.template || null);
100
        },
101
102
        /**
103
         * @param {String} template
104
         */
105
        checkRenderTemplate: function(template) {
106
            if (!!template && this.template === template) {
107
                return this.sandbox.emit('sulu.header.toolbar.item.enable', 'template', false);
108
            }
109
110
            this.sandbox.emit('sulu.header.toolbar.item.loading', 'template');
111
112
            if (this.template !== '' && !this.saved) {
113
                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...
114
            } else {
115
                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...
116
            }
117
        },
118
119
        /**
120
         * @param {String} template
121
         */
122
        showRenderTemplateDialog: function(template) {
123
            // show warning dialog
124
            this.sandbox.emit('sulu.overlay.show-warning',
125
                'sulu.overlay.be-careful',
126
                'content.template.dialog.content',
127
                function() {
128
                    // cancel callback
129
                    this.sandbox.emit('sulu.header.toolbar.item.enable', 'template', false);
130
131
                    if (!!this.template) {
132
                        this.sandbox.emit('sulu.header.toolbar.item.change', 'template', this.template, false);
133
                    }
134
                }.bind(this),
135
                function() {
136
                    // ok callback
137
                    this.loadFormTemplate(template);
138
                }.bind(this)
139
            );
140
        },
141
142
        /**
143
         * @param {String} template
144
         */
145
        loadFormTemplate: function(template) {
146
            if (!template) {
147
                template = this.options.config.types[(this.options.type || this.data.articleType)].default;
148
            }
149
150
            this.template = template;
151
            this.formId = '#content-form-container';
152
            this.$container = this.sandbox.dom.createElement('<div id="content-form-container"/>');
153
            this.html(this.$container);
154
155
            if (!!this.sandbox.form.getObject(this.formId)) {
156
                var data = this.data;
157
                this.data = this.sandbox.form.getData(this.formId);
158
                if (!!data.id) {
159
                    this.data.id = data.id;
160
                }
161
162
                this.data = this.sandbox.util.extend({}, data, this.data);
163
            }
164
165
            require([this.getTemplateUrl(template)], this.renderFormTemplate.bind(this));
166
        },
167
168
        /**
169
         * @param {String} template
170
         *
171
         * @returns {String}
172
         */
173
        getTemplateUrl: function(template) {
174
            var url = 'text!/admin/content/template/form';
175
            if (!!template) {
176
                url += '/' + template + '.html';
177
            } else {
178
                url += '.html';
179
            }
180
            url += '?type=article&language=' + this.options.locale;
181
182
            if (!!this.data.id) {
183
                url += '&uuid=' + this.data.id;
184
            }
185
186
            return url;
187
        },
188
189
        /**
190
         * @param {String} template
191
         */
192
        renderFormTemplate: function(template) {
193
            this.sandbox.dom.html(this.formId, this.sandbox.util.template(template, {
194
                translate: this.sandbox.translate,
195
                content: this.data,
196
                options: this.options,
197
                entityClass: 'Sulu\\Bundle\\ArticleBundle\\Document\\ArticleDocument',
198
                entityId: this.options.id
199
            }));
200
201
            var data = this.options.adapter.prepareData(this.data, this);
202
            if (data.type && data.type.name === 'ghost') {
203
                this.ghost = {
204
                    locale: data.type.value,
205
                    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...
206
                    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...
207
                };
208
209
                data = {
210
                    id: this.data.id,
211
                    articleType: this.data.articleType
212
                };
213
            }
214
215
            this.options.adapter.beforeFormCreate(this);
216
217
            this.createForm(data).then(this.changeTemplateDropdownHandler.bind(this));
218
        },
219
220
        changeTemplateDropdownHandler: function() {
221
            if (!!this.template) {
222
                this.sandbox.emit('sulu.header.toolbar.item.change', 'template', this.template);
223
            }
224
            this.sandbox.emit('sulu.header.toolbar.item.enable', 'template', false);
225
        },
226
227
        /**
228
         * @param {Object} data
229
         *
230
         * @returns {Object}
231
         */
232
        createForm: function(data) {
233
            var formObject = this.sandbox.form.create(this.formId),
234
                deferred = this.sandbox.data.deferred();
235
236
            formObject.initialized.then(function() {
237
                this.sandbox.form.setData(this.formId, data).then(function() {
238
                    if (!!this.ghost) {
239
                        var titleProperty = this.getTitleProperty(),
240
                            pageTitleProperty = this.getPageTitleProperty();
241
242
                        if (titleProperty) {
243
                            this.sandbox.dom.attr(titleProperty.$el, 'placeholder', this.ghost.locale + ': ' + this.ghost.title);
244
                        }
245
246
                        if (pageTitleProperty) {
247
                            this.sandbox.dom.attr(pageTitleProperty.$el, 'placeholder', this.ghost.locale + ': ' + this.ghost.pageTitle);
248
                        }
249
                    }
250
251
                    this.sandbox.start(this.$el, {reset: true}).then(function() {
252
                        this.initSortableBlock();
253
                        this.bindFormEvents();
254
                        deferred.resolve();
255
256
                        if (!!this.options.preview) {
257
                            this.options.preview.bindDomEvents(this.$el);
258
                            var data = this.options.adapter.prepareData(this.data, this);
259
                            data.template = this.template;
260
                            if (!!data.type && data.type.name === 'ghost') {
261
                                data = {id: data.id};
262
                            }
263
264
                            this.options.preview.updateContext(
265
                                {template: this.template},
266
                                this.options.adapter.prepareData(data, this)
267
                            );
268
                        }
269
                    }.bind(this));
270
                }.bind(this));
271
            }.bind(this));
272
273
            return deferred.promise();
274
        },
275
276
        initSortableBlock: function() {
277
            var $sortable = this.sandbox.dom.find('.sortable', this.$el),
278
                sortable;
279
280
            if (!!$sortable && $sortable.length > 0) {
281
                this.sandbox.dom.sortable($sortable, 'destroy');
282
                sortable = this.sandbox.dom.sortable($sortable, {
283
                    handle: '.move',
284
                    forcePlaceholderSize: true
285
                });
286
287
                // (un)bind event listener
288
                this.sandbox.dom.unbind(sortable, 'sortupdate');
289
290
                sortable.bind('sortupdate', function(event) {
291
                    // update preview
292
                    this.updatePreviewProperty(event.currentTarget, null);
293
294
                    this.sandbox.emit('sulu.content.changed');
295
                }.bind(this));
296
            }
297
        },
298
299
        bindFormEvents: function() {
300
            this.sandbox.dom.on(this.formId, 'form-remove', function(event, propertyName) {
301
                this.initSortableBlock();
302
                this.setDirty();
303
304
                // update preview
305
                this.updatePreviewProperty(event.currentTarget, propertyName);
306
            }.bind(this));
307
308
            this.sandbox.dom.on(this.formId, 'form-add', function(event, propertyName, data, index) {
309
                var $elements = this.sandbox.dom.children(this.$find('[data-mapper-property="' + propertyName + '"]')),
310
                    $element = (index !== undefined && $elements.length > index) ? $elements[index] : this.sandbox.dom.last($elements);
311
312
                // start new subcomponents
313
                this.sandbox.start($element);
314
315
                // enable save button
316
                this.setDirty();
317
318
                // reinit sorting
319
                this.initSortableBlock();
320
321
                // update preview
322
                this.updatePreviewProperty(event.currentTarget, propertyName);
323
            }.bind(this));
324
325
            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...
326
                // reinit sorting
327
                this.initSortableBlock();
328
            }.bind(this));
329
        },
330
331
        loadComponentData: function() {
332
            return this.options.data();
333
        },
334
335
        /**
336
         * @param {Object} target
337
         * @param {String} propertyName
338
         */
339
        updatePreviewProperty: function(target, propertyName) {
340
            if (!!this.options.preview) {
341
                var data = this.sandbox.form.getData(this.formId);
342
343
                if (!propertyName && !!target) {
344
                    propertyName = this.sandbox.dom.data(target, 'mapperProperty');
345
                }
346
347
                this.options.preview.updateProperty(propertyName, data[propertyName]);
348
            }
349
        },
350
351
        getTitleProperty: function() {
352
            if (!this.propertyConfiguration) {
353
                this.propertyConfiguration = PropertyConfiguration.generate(this.$el);
354
            }
355
356
            if (!!this.propertyConfiguration.tags['sulu_article.article_title']) {
357
                return this.propertyConfiguration.tags['sulu_article.article_title'].highestProperty;
358
            }
359
360
            return this.propertyConfiguration.title;
361
        },
362
363
        getPageTitleProperty: function() {
364
            if (!this.propertyConfiguration) {
365
                this.propertyConfiguration = PropertyConfiguration.generate(this.$el);
366
            }
367
368
            if (!!this.propertyConfiguration.tags['sulu_article.page_title']) {
369
                return this.propertyConfiguration.tags['sulu_article.page_title'].highestProperty;
370
            } 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...
371
                return this.propertyConfiguration.pageTitle;
372
            }
373
        },
374
375
        getRoutePathProperty: function() {
376
            if (!this.propertyConfiguration) {
377
                this.propertyConfiguration = PropertyConfiguration.generate(this.$el);
378
            }
379
380
            if (!!this.propertyConfiguration.tags['sulu_article.article_route']) {
381
                return this.propertyConfiguration.tags['sulu_article.article_route'].highestProperty;
382
            } 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...
383
                return this.propertyConfiguration.routePath;
384
            }
385
        }
386
    };
387
});
388