Completed
Pull Request — develop (#233)
by Wachter
45:40 queued 30:46
created

main.js ➔ ... ➔ ???   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
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
    'services/husky/storage',
13
    'sulucontent/components/copy-locale-overlay/main',
14
    'sulucontent/components/open-ghost-overlay/main',
15
    'services/suluarticle/article-manager',
16
    'services/suluarticle/article-router',
17
    'services/suluarticle/filter-helper'
18
], function(_, storage, CopyLocale, OpenGhost, ArticleManager, ArticleRouter, filterHelper) {
19
20
    'use strict';
21
22
    var defaults = {
23
        options: {
24
            config: {},
25
            storageName: 'articles'
26
        },
27
28
        templates: {
29
            list: [
30
                '<div class="content-title">',
31
                '    <h2><%= translations.headline %> <span class="type"><%= type %></span></h2>',
32
                '</div>',
33
                '<div class="list-toolbar-container"></div>',
34
                '<div class="list-info"></div>',
35
                '<div class="datagrid-container"></div>',
36
                '<div class="dialog"></div>'
37
            ].join(''),
38
            draftIcon: '<span class="draft-icon" title="<%= title %>"/>',
39
            publishedIcon: '<span class="published-icon" title="<%= title %>"/>',
40
            route: [
41
                'articles', '<% if (!!type) { %>:<%=type%><% } %>', '/<%=locale%>'
42
            ].join('')
43
        },
44
45
        translations: {
46
            headline: 'sulu_article.list.title',
47
            published: 'public.published',
48
            unpublished: 'public.unpublished',
49
            publishedWithDraft: 'public.published-with-draft',
50
            filterMe: 'sulu_article.list.filter.me',
51
            filterAll: 'sulu_article.list.filter.all',
52
            filterByAuthor: 'sulu_article.list.filter.by-author',
53
            filterByCategory: 'sulu_article.list.filter.by-category',
54
            filterByTag: 'sulu_article.list.filter.by-tag',
55
            filterByPage: 'sulu_article.list.filter.by-page',
56
            filterByTimescale: 'sulu_article.list.filter.by-timescale',
57
            from: 'sulu_article.authored-selection-overlay.from',
58
            to: 'sulu_article.authored-selection-overlay.to',
59
            openGhostOverlay: {
60
                info: 'sulu_article.settings.open-ghost-overlay.info',
61
                new: 'sulu_article.settings.open-ghost-overlay.new',
62
                copy: 'sulu_article.settings.open-ghost-overlay.copy',
63
                ok: 'sulu_article.settings.open-ghost-overlay.ok'
64
            }
65
        }
66
    };
67
68
69
    return {
70
71
        defaults: defaults,
72
73
        data: {
74
            contactId: null
75
        },
76
77
        header: function() {
78
            this.storage = storage.get('sulu', this.options.storageName);
79
80
            var types = this.options.config.types,
81
                typeNames = this.options.config.typeNames,
82
                button = {
83
                    icon: 'plus-circle',
84
                    title: 'public.add-new'
85
                },
86
                tabs = false,
87
                tabItems,
88
                tabPreselect = null,
89
                preselectedType = this.options.type || this.storage.getWithDefault('type', null);
90
91
            if (1 === typeNames.length) {
92
                button.callback = function() {
93
                    this.toAdd(typeNames[0]);
94
                }.bind(this);
95
            } else {
96
                button.dropdownItems = _.map(typeNames, function(type) {
97
                    return {
98
                        title: types[type].title,
99
                        callback: function() {
100
                            this.toAdd(type);
101
                        }.bind(this)
102
                    };
103
                }.bind(this));
104
105
                tabItems = [];
106
107
                // add tab item 'all' if parameter is true
108
                if (this.options.config.displayTabAll === true) {
109
                    tabItems.push(
110
                        {
111
                            name: 'public.all',
112
                            key: null
113
                        }
114
                    );
115
                }
116
117
                // add tab item for each type
118
                _.each(typeNames, function(type) {
119
                    tabItems.push(
120
                        {
121
                            id: type,
122
                            name: types[type].title,
123
                            key: type
124
                        }
125
                    );
126
127
                    if (type === preselectedType) {
128
                        tabPreselect = types[type].title;
129
                    }
130
                }.bind(this));
0 ignored issues
show
unused-code introduced by
The call to bind does not seem necessary since the function does not use this. Consider calling it directly.
Loading history...
131
132
                tabs = {
133
                    componentOptions: {
134
                        callback: this.typeChange.bind(this),
135
                        preselector: 'name',
136
                        preselect: tabPreselect
137
                    },
138
                    data: tabItems
139
                };
140
            }
141
142
            return {
143
                noBack: true,
144
145
                tabs: tabs,
146
147
                toolbar: {
148
                    buttons: {
149
                        addArticle: {options: button},
150
                        deleteSelected: {}
151
                    },
152
153
                    languageChanger: {
154
                        data: this.options.config.languageChanger,
155
                        preSelected: this.options.locale
156
                    }
157
                }
158
            };
159
        },
160
161
        layout: {
162
            content: {
163
                width: 'max'
164
            }
165
        },
166
167
        initialize: function() {
168
            if (!!this.options.type) {
169
                this.storage.set('type', this.options.type);
170
            } else if (this.storage.has('type')) {
171
                ArticleRouter.toList(this.options.locale, this.storage.get('type'));
172
                this.options.type = this.storage.get('type');
173
            }
174
175
            this.render();
176
177
            this.bindCustomEvents();
178
        },
179
180
        render: function() {
181
            var type = this.options.config.types[this.options.type];
182
183
            this.$el.html(this.templates.list({
184
                translations: this.translations,
185
                type: type ? this.sandbox.translate(type.title) : ''
186
            }));
187
188
            var urlArticleApi = '/admin/api/articles?sortBy=authored&sortOrder=desc&locale=' + this.options.locale + (this.options.type ? ('&type=' + this.options.type) : '');
189
            var toolbar = this.retrieveListToolbarTemplate(this.loadFilterFromStorage());
190
191
            this.sandbox.sulu.initListToolbarAndList.call(this,
192
                'article',
193
                '/admin/api/articles/fields',
194
                {
195
                    el: this.$find('.list-toolbar-container'),
196
                    instanceName: 'articles',
197
                    template: toolbar
198
                },
199
                {
200
                    el: this.sandbox.dom.find('.datagrid-container'),
201
                    url: urlArticleApi,
202
                    storageName: this.options.storageName,
203
                    searchInstanceName: 'articles',
204
                    searchFields: ['title', 'route_path', 'changer_full_name', 'creator_full_name', 'pages.title'],
205
                    resultKey: 'articles',
206
                    instanceName: 'articles',
207
                    actionCallback: function(id, article) {
208
                        if ('ghost' === article.localizationState.state) {
209
                            ArticleManager.load(id, this.options.locale).then(function(response) {
210
                                OpenGhost.openGhost.call(
211
                                    this,
212
                                    response,
213
                                    this.translations.openGhostOverlay
214
                                ).then(
215
                                    function(copy, src) {
216
                                        if (!!copy) {
217
                                            CopyLocale.copyLocale.call(
218
                                                this,
219
                                                id,
220
                                                src,
221
                                                [this.options.locale],
222
                                                function() {
223
                                                    this.toEdit(id);
224
                                                }.bind(this)
225
                                            );
226
                                        } else {
227
                                            this.toEdit(id);
228
                                        }
229
                                    }.bind(this)
230
                                );
231
                            }.bind(this)).fail(function(xhr) {
232
                                this.sandbox.emit('sulu.article.error', xhr.status, xhr.responseJSON.code || 0, data);
0 ignored issues
show
Bug introduced by
The variable data seems to be never declared. If this is a global, consider adding a /** global: data */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
233
                            }.bind(this));
234
                        } else {
235
                            this.toEdit(id);
236
                        }
237
                    }.bind(this),
238
                    viewOptions: {
239
                        table: {
240
                            actionIconColumn: 'title',
241
                            badges: [
242
                                {
243
                                    column: 'title',
244
                                    callback: function(item, badge) {
245
                                        if (!!item.localizationState &&
246
                                            item.localizationState.state === 'ghost' &&
247
                                            item.localizationState.locale !== this.options.locale
248
                                        ) {
249
                                            badge.title = item.localizationState.locale;
250
251
                                            return badge;
252
                                        }
253
254
                                        return false;
255
                                    }.bind(this)
256
                                },
257
                                {
258
                                    column: 'title',
259
                                    callback: function(item, badge) {
260
                                        var icons = '',
261
                                            tooltip = this.translations.unpublished;
262
263
                                        if (!!item.published && !item.publishedState) {
264
                                            tooltip = this.translations.publishedWithDraft;
265
                                            icons += this.templates.publishedIcon({title: tooltip});
266
                                        }
267
                                        if (!item.publishedState) {
268
                                            icons += this.templates.draftIcon({title: tooltip});
269
                                        }
270
271
                                        badge.title = icons;
272
                                        badge.cssClass = 'badge-none';
273
274
                                        return badge;
275
                                    }.bind(this)
276
                                }
277
                            ]
278
                        }
279
                    }
280
                }
281
            );
282
        },
283
284
        toEdit: function(id, locale) {
285
            ArticleRouter.toEdit(id, (locale || this.options.locale));
286
        },
287
288
        toAdd: function(type, locale) {
289
            ArticleRouter.toAdd((locale || this.options.locale), type);
290
        },
291
292
        toList: function(locale) {
293
            ArticleRouter.toList((locale || this.options.locale), this.options.type);
294
        },
295
296
        deleteItems: function(ids) {
297
            ArticleManager.remove(ids, this.options.locale).then(function() {
298
                _.each(ids, function(id) {
299
                    this.sandbox.emit('husky.datagrid.articles.record.remove', id);
300
                }.bind(this));
301
            }.bind(this));
302
        },
303
304
        typeChange: function(item) {
305
            // Save the tab key. Can be removed when issue #72 is solved:
306
            // https://github.com/sulu/SuluArticleBundle/issues/72
307
            this.options.type = item.key;
308
309
            this.sandbox.emit('husky.datagrid.articles.url.update', {page: 1, type: this.options.type});
310
            ArticleRouter.toList(this.options.locale, this.options.type, false, false);
311
            this.storage.set('type', this.options.type);
312
313
            this.setTypeName(item.key ? item.name : '');
314
        },
315
316
        /**
317
         * Returns copy article from a given locale to a array of other locales url.
318
         *
319
         * @param {string} id
320
         * @param {string} src
321
         * @param {string[]} dest
322
         *
323
         * @returns {string}
324
         */
325
        getCopyLocaleUrl: function(id, src, dest) {
326
            return ArticleManager.getCopyLocaleUrl(id, src, dest);
327
        },
328
329
        bindCustomEvents: function() {
330
            this.sandbox.on('husky.datagrid.articles.number.selections', function(number) {
331
                var postfix = number > 0 ? 'enable' : 'disable';
332
                this.sandbox.emit('sulu.header.toolbar.item.' + postfix, 'deleteSelected', false);
333
            }.bind(this));
334
335
            this.sandbox.on('sulu.toolbar.delete', function() {
336
                this.sandbox.emit('husky.datagrid.articles.items.get-selected', this.deleteItems.bind(this));
337
            }.bind(this));
338
339
            this.sandbox.on('sulu.header.language-changed', function(item) {
340
                if (item.id === this.options.locale) {
341
                    return;
342
                }
343
344
                this.sandbox.sulu.saveUserSetting(this.options.config.settingsKey, item.id);
345
                this.toList(item.id);
346
            }.bind(this));
347
348
            this.sandbox.on('husky.toolbar.articles.initialized', function() {
349
                this.sandbox.emit('husky.toolbar.articles.item.mark', this.loadFilterFromStorage().filterKey);
350
            }.bind(this));
351
        },
352
353
        /**
354
         * Generates list toolbar buttons.
355
         *
356
         * @param {Object} filter
357
         */
358
        retrieveListToolbarTemplate: function(filter) {
359
            return this.sandbox.sulu.buttons.get({
360
                settings: {
361
                    options: {
362
                        dropdownItems: [
363
                            {
364
                                type: 'columnOptions'
365
                            }
366
                        ]
367
                    }
368
                },
369
                authoredDate: {
370
                    options: {
371
                        icon: 'calendar',
372
                        group: 2,
373
                        title: filterHelper.getAuthoredTitle(filter.authored),
374
                        showTitle: true,
375
                        dropdownOptions: {
376
                            idAttribute: 'id',
377
                            markSelected: false
378
                        },
379
                        dropdownItems: [
380
                            {
381
                                title: this.translations.filterAll,
382
                                callback: function() {
383
                                    var filter = this.appendFilter('authored', {from: null, to: null});
384
                                    this.sandbox.emit(
385
                                        'husky.toolbar.articles.button.set',
386
                                        'authoredDate',
387
                                        {title: filterHelper.getAuthoredTitle(filter.authored)}
388
                                    );
389
                                }.bind(this)
390
                            },
391
                            {
392
                                id: 'timescale',
393
                                title: this.translations.filterByTimescale,
394
                                callback: this.openAuthoredSelectionOverlay.bind(this)
395
                            }
396
                        ]
397
                    }
398
                },
399
                workflowStage: {
400
                    options: {
401
                        icon: 'circle-o',
402
                        group: 2,
403
                        title: filterHelper.getPublishedTitle(filter.workflowStage),
404
                        showTitle: true,
405
                        dropdownOptions: {
406
                            idAttribute: 'id',
407
                            markSelected: true,
408
                            changeButton: true
409
                        },
410
                        dropdownItems: [
411
                            {
412
                                title: this.translations.filterAll,
413
                                marked: !filter.workflowStage,
414
                                callback: function() {
415
                                    this.appendFilter('workflowStage', null);
416
                                }.bind(this)
417
                            },
418
                            {
419
                                id: 'published',
420
                                title: this.translations.published,
421
                                marked: filter.workflowStage === 'published',
422
                                callback: function() {
423
                                    this.appendFilter('workflowStage', 'published');
424
                                }.bind(this)
425
                            },
426
                            {
427
                                id: 'test',
428
                                title: this.translations.unpublished,
429
                                marked: filter.workflowStage === 'test',
430
                                callback: function() {
431
                                    this.appendFilter('workflowStage', 'test');
432
                                }.bind(this)
433
                            }
434
                        ]
435
                    }
436
                },
437
                filter: {
438
                    options: {
439
                        icon: 'filter',
440
                        group: 2,
441
                        title: filterHelper.getFilterTitle(filter),
442
                        showTitle: true,
443
                        dropdownOptions: {
444
                            idAttribute: 'id',
445
                            markSelected: true,
446
                            changeButton: false,
447
                            preSelected: filter.filterKey
448
                        },
449
                        dropdownItems: [
450
                            {
451
                                id: 'all',
452
                                title: this.translations.filterAll,
453
                                marked: filter.filterKey === 'all',
454
                                callback: function() {
455
                                    this.replaceFilter('all');
456
                                }.bind(this)
457
                            },
458
                            {
459
                                id: 'me',
460
                                title: this.translations.filterMe,
461
                                marked: filter.filterKey === 'me',
462
                                callback: function() {
463
                                    this.replaceFilter('contact', this.sandbox.sulu.user.contact, 'me');
464
                                }.bind(this)
465
                            },
466
                            {
467
                                id: 'filterByAuthor',
468
                                title: this.translations.filterByAuthor + ' ...',
469
                                marked: filter.filterKey === 'filterByAuthor',
470
                                callback: this.openContactSelectionOverlay.bind(this)
471
                            },
472
                            {
473
                                divider: true
474
                            },
475
                            {
476
                                id: 'filterByCategory',
477
                                title: this.translations.filterByCategory + ' ...',
478
                                marked: filter.filterKey === 'filterByCategory',
479
                                callback: this.openCategorySelectionOverlay.bind(this)
480
                            },
481
                            {
482
                                id: 'filterByTag',
483
                                title: this.translations.filterByTag + ' ...',
484
                                marked: filter.filterKey === 'filterByTag',
485
                                callback: this.openTagSelectionOverlay.bind(this)
486
                            },
487
                            {
488
                                id: 'filterByPage',
489
                                title: this.translations.filterByPage + ' ...',
490
                                marked: filter.filterKey === 'filterByPage',
491
                                callback: this.openPageSelectionOverlay.bind(this)
492
                            }
493
                        ]
494
                    }
495
                }
496
            });
497
        },
498
499
        /**
500
         * Opens contact selection overlay.
501
         */
502
        openContactSelectionOverlay: function() {
503
            var $container = $('<div/>');
504
505
            this.$el.append($container);
506
507
            this.sandbox.start([{
508
                name: 'articles/list/contact-selection@suluarticle',
509
                options: {
510
                    el: $container,
511
                    locale: this.options.locale,
512
                    data: {
513
                        contact: this.loadFilterFromStorage().contact
514
                    },
515
                    selectCallback: function(data) {
516
                        this.replaceFilter('contact', data.contactItem, 'filterByAuthor');
517
                    }.bind(this)
518
                }
519
            }]);
520
        },
521
522
        /**
523
         * Opens category selection overlay.
524
         */
525
        openCategorySelectionOverlay: function() {
526
            var $container = $('<div/>');
527
528
            this.$el.append($container);
529
530
            this.sandbox.start([{
531
                name: 'articles/list/category-selection@suluarticle',
532
                options: {
533
                    el: $container,
534
                    locale: this.options.locale,
535
                    data: {
536
                        category: this.loadFilterFromStorage().category
537
                    },
538
                    selectCallback: function(data) {
539
                        this.replaceFilter('category', data.categoryItem, 'filterByCategory');
540
                    }.bind(this)
541
                }
542
            }]);
543
        },
544
545
        /**
546
         * Opens tag selection overlay.
547
         */
548
        openTagSelectionOverlay: function() {
549
            var $container = $('<div/>');
550
551
            this.$el.append($container);
552
553
            this.sandbox.start([{
554
                name: 'articles/list/tag-selection@suluarticle',
555
                options: {
556
                    el: $container,
557
                    locale: this.options.locale,
558
                    data: {
559
                        tag: this.loadFilterFromStorage().tag
560
                    },
561
                    selectCallback: function(data) {
562
                        this.replaceFilter('tag', data.tagItem, 'filterByTag');
563
                    }.bind(this)
564
                }
565
            }]);
566
        },
567
568
        /**
569
         * Opens page selection overlay.
570
         */
571
        openPageSelectionOverlay: function() {
572
            var $container = $('<div/>');
573
574
            this.$el.append($container);
575
576
            this.sandbox.start([{
577
                name: 'page-tree-route/page-select@suluarticle',
578
                options: {
579
                    el: $container,
580
                    locale: this.options.locale,
581
                    data: this.loadFilterFromStorage().page,
582
                    translations: {
583
                        overlayTitle: 'sulu_article.page-selection-overlay.title'
584
                    },
585
                    selectCallback: function(data) {
586
                        this.replaceFilter('page', data, 'filterByPage');
587
                    }.bind(this)
588
                }
589
            }]);
590
        },
591
592
        /**
593
         * Opens authored selection overlay.
594
         */
595
        openAuthoredSelectionOverlay: function() {
596
            var $container = $('<div/>');
597
598
            this.$el.append($container);
599
600
            this.sandbox.start([{
601
                name: 'articles/list/authored-selection@suluarticle',
602
                options: {
603
                    el: $container,
604
                    locale: this.options.locale,
605
                    data: this.loadFilterFromStorage().authored,
606
                    selectCallback: function(data) {
607
                        var filter = this.appendFilter('authored', data);
608
                        this.sandbox.emit(
609
                            'husky.toolbar.articles.button.set',
610
                            'authoredDate',
611
                            {title: filterHelper.getAuthoredTitle(filter.authored)}
612
                        );
613
                    }.bind(this)
614
                }
615
            }]);
616
        },
617
618
        /**
619
         * Replace given filter.
620
         *
621
         * @param {String} key
622
         * @param {Object|String} value
623
         * @param {String} filterKey
624
         *
625
         * @return {Object}
626
         */
627
        replaceFilter: function(key, value, filterKey) {
628
            var filter = this.loadFilterFromStorage();
629
630
            filter.category = null;
631
            filter.contact = null;
632
            filter.tag = null;
633
            filter.page = null;
634
            filter.filterKey = filterKey || key;
635
636
            if (value) {
637
                filter[key] = value;
638
            }
639
640
            return this.applyFilterToList(filter);
641
        },
642
643
        /**
644
         * Append given filter.
645
         *
646
         * @param {String} key
647
         * @param {Object|String} value
648
         *
649
         * @return {Object}
650
         */
651
        appendFilter: function(key, value) {
652
            var filter = this.loadFilterFromStorage();
653
            filter[key] = value;
654
655
            return this.applyFilterToList(filter);
656
        },
657
658
        /**
659
         * Emits the url update event for the list, changes the title of the filter button
660
         * and saves the selected filters in the storage.
661
         *
662
         * @param {Object} filter
663
         *
664
         * @return {Object}
665
         */
666
        applyFilterToList: function(filter) {
667
            var update = {
668
                contactId: filter.contact ? filter.contact.id : null,
669
                categoryId: filter.category ? filter.category.id : null,
670
                tagId: filter.tag ? filter.tag.id : null,
671
                pageId: filter.page ? filter.page.id : null,
672
                authoredFrom: filter.authored ? filter.authored.from : null,
673
                authoredTo: filter.authored ? filter.authored.to : null,
674
                workflowStage: filter.workflowStage ? filter.workflowStage : null
675
            };
676
677
            this.saveFilterToStorage(filter);
678
679
            this.sandbox.emit('husky.datagrid.articles.url.update', update);
680
            this.sandbox.emit('husky.toolbar.articles.button.set', 'filter', {title: filterHelper.getFilterTitle(filter)});
681
682
            return filter;
683
        },
684
685
        /**
686
         * Retrieves the filter from the storage.
687
         *
688
         * @returns {Object}
689
         */
690
        loadFilterFromStorage: function() {
691
            return this.storage.getWithDefault('filter', {
692
                filterKey: 'all',
693
                contact: null,
694
                category: null,
695
                tag: null,
696
                authored: {from: null, to: null}
697
            });
698
        },
699
700
        /**
701
         * Save the filter in the storage.
702
         *
703
         * @param {Object} filter
704
         */
705
        saveFilterToStorage: function(filter) {
706
            this.storage.set('filter', filter);
707
        },
708
709
        setTypeName: function(name) {
710
            this.$el.find('.type').text(this.sandbox.translate(name));
711
        }
712
    };
713
});
714