• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

divio / django-cms / #30922

30 Mar 2026 09:09PM UTC coverage: 89.941% (-0.03%) from 89.971%
#30922

push

travis-ci

web-flow
build(deps): bump pygments from 2.19.2 to 2.20.0 in /docs (#8555)

Bumps [pygments](https://github.com/pygments/pygments) from 2.19.2 to 2.20.0.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.19.2...2.20.0)

---
updated-dependencies:
- dependency-name: pygments
  dependency-version: 2.20.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

1339 of 2153 branches covered (62.19%)

9219 of 10250 relevant lines covered (89.94%)

11.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.23
/cms/static/cms/js/modules/cms.navigation.js
1
/*
2
 * Copyright https://github.com/django-cms/django-cms
3
 */
4

5
import $ from 'jquery';
6
import throttle from 'lodash-es/throttle.js';
7

8
/**
9
 * Responsible for creating usable navigation for narrow screens.
10
 *
11
 * @class Navigation
12
 * @namespace CMS
13
 */
14
class Navigation {
15
    constructor() {
16
        this._setupUI();
15✔
17
        this._getWidths();
18

19
        /**
20
         * The zero based index of the right-most visible menu item of the left toolbar part.
21
         *
22
         * @property rightMostItemIndex {Number}
23
         */
24
        this.rightMostItemIndex = this.items.left.length - 1;
25

15✔
26
        /**
27
         * The zero based index of the left-most visible item of the right toolbar part.
28
         *
15✔
29
         * @property leftMostItemIndex {Number}
30
         */
31
        this.leftMostItemIndex = 0;
32

33
        this.resize = 'resize.cms.navigation';
34
        this.load = 'load.cms.navigation';
35
        this.orientationChange = 'orientationchange.cms.navigation';
15✔
36

37
        this._events();
38
    }
39

40
    /**
41
     * Cache UI jquery objects.
42
     *
15✔
43
     * @method _setupUI
44
     * @private
15✔
45
     */
15✔
46
    _setupUI() {
15✔
47
        var container = $('.cms');
48
        var trigger = container.find('.cms-toolbar-more');
15✔
49

50
        this.ui = {
51
            window: $(window),
52
            toolbarLeftPart: container.find('.cms-toolbar-left'),
53
            toolbarRightPart: container.find('.cms-toolbar-right'),
54
            trigger: trigger,
55
            dropdown: trigger.find('> ul'),
56
            toolbarTrigger: container.find('.cms-toolbar-trigger'),
57
            logo: container.find('.cms-toolbar-item-logo')
58
        };
15✔
59
    }
15✔
60

61
    /**
15✔
62
     * Setup resize handler to construct the dropdown.
63
     *
64
     * @method _events
65
     * @private
66
     */
67
    _events() {
68
        var THROTTLE_TIMEOUT = 50;
69

70
        this.ui.window
71
            .off([this.resize, this.load, this.orientationChange].join(' '))
72
            .on(
73
                [this.resize, this.load, this.orientationChange].join(' '),
74
                throttle(this._handleResize.bind(this), THROTTLE_TIMEOUT)
75
            );
76
    }
77

78
    /**
79
     * Calculates all the movable menu items widths.
15✔
80
     *
81
     * @method _getWidths
15✔
82
     * @private
83
     */
84
    _getWidths() {
85
        var that = this;
86

87
        that.items = {
88
            left: [],
89
            leftTotalWidth: 0,
90
            right: [],
91
            rightTotalWidth: 0,
92
            moreButtonWidth: 0
93
        };
94
        var leftItems = that.ui.toolbarLeftPart.find('.cms-toolbar-item-navigation > li:not(.cms-toolbar-more)');
95
        var rightItems = that.ui.toolbarRightPart.find('> .cms-toolbar-item');
96

97
        var getSize = function getSize(el, store) {
98
            var element = $(el);
99
            var width = $(el).outerWidth(true);
7✔
100

101
            store.push({
102
                element: element,
103
                width: width
7✔
104
            });
105
        };
7✔
106
        var sumWidths = function sumWidths(sum, item) {
107
            return sum + item.width;
108
        };
109

110
        leftItems.each(function() {
111
            getSize(this, that.items.left);
112
        });
7✔
113

7✔
114
        rightItems.each(function() {
115
            getSize(this, that.items.right);
7✔
116
        });
42✔
117

42✔
118
        that.items.leftTotalWidth = that.items.left.reduce(sumWidths, 0);
119
        that.items.rightTotalWidth = that.items.right.reduce(sumWidths, 0);
42✔
120
        that.items.moreButtonWidth = that.ui.trigger.outerWidth();
121
    }
122

123
    /**
124
     * Calculates available width based on the state of the page.
7✔
125
     *
42✔
126
     * @method _calculateAvailableWidth
127
     * @private
128
     * @returns {Number} available width in px
7✔
129
     */
21✔
130
    _calculateAvailableWidth() {
131
        var fullWidth = this.ui.window.width();
132
        var reduce = parseInt(this.ui.toolbarRightPart.css('padding-inline-end'), 10) + this.ui.logo.outerWidth(true);
7✔
133

21✔
134
        return fullWidth - reduce;
135
    }
136

7✔
137
    /**
7✔
138
     * Shows the dropdown.
7✔
139
     *
140
     * @method _showDropdown
7✔
141
     * @private
7✔
142
     */
7✔
143
    _showDropdown() {
144
        this.ui.trigger.css('display', 'list-item');
145
    }
146

147
    /**
148
     * Hides the dropdown.
149
     *
150
     * @method _hideDropdown
151
     * @private
152
     */
153
    _hideDropdown() {
4✔
154
        this.ui.trigger.css('display', 'none');
4✔
155
    }
156

4✔
157
    /**
158
     * Figures out if we need to show/hide/modify the dropdown.
159
     *
160
     * @method _handleResize
161
     * @private
162
     */
163
    // eslint-disable-next-line complexity
164
    _handleResize() {
165
        var remainingWidth;
166
        var availableWidth = this._calculateAvailableWidth();
10✔
167

168
        if (availableWidth > this.items.leftTotalWidth + this.items.rightTotalWidth) {
169
            this._showAll();
170
        } else {
171
            // first handle the left part
172
            remainingWidth = availableWidth - this.items.moreButtonWidth - this.items.rightTotalWidth;
173

174
            // Figure out how many nav menu items fit into the available space.
175
            var newRightMostItemIndex = -1;
176

11✔
177
            while (remainingWidth - this.items.left[newRightMostItemIndex + 1].width >= 0) {
178
                remainingWidth -= this.items.left[newRightMostItemIndex + 1].width;
179
                newRightMostItemIndex++;
180
            }
181

182
            if (newRightMostItemIndex < this.rightMostItemIndex) {
183
                this._moveToDropdown(this.rightMostItemIndex - newRightMostItemIndex);
184
            } else if (this.rightMostItemIndex < newRightMostItemIndex) {
185
                this._moveOutOfDropdown(newRightMostItemIndex - this.rightMostItemIndex);
186
            }
187

188
            this._showDropdown();
189

190
            // if we do not have any width left and all the items from the left part
12!
191
            // are already in the dropdown - start with the right part
×
192
            if (remainingWidth < 0 && this.rightMostItemIndex === -1) {
193
                remainingWidth += this.items.rightTotalWidth;
×
194

×
195
                var newLeftMostItemIndex = this.items.right.length;
196

×
197
                // istanbul ignore if: this moves items to the right one by one
198
                // eslint-disable-next-line no-constant-condition
199
                if (false) {
200
                    // if you want to move items from the right one by one
12✔
201
                    while (remainingWidth - this.items.right[newLeftMostItemIndex - 1].width > 0) {
202
                        remainingWidth -= this.items.right[newLeftMostItemIndex - 1].width;
12✔
203
                        newLeftMostItemIndex--;
3✔
204
                    }
205

206
                    if (newLeftMostItemIndex > this.leftMostItemIndex) {
9✔
207
                        this._moveToDropdown(newLeftMostItemIndex - this.leftMostItemIndex, 'right');
208
                    } else if (newLeftMostItemIndex < this.leftMostItemIndex) {
209
                        this._moveOutOfDropdown(this.leftMostItemIndex - newLeftMostItemIndex, 'right');
9✔
210
                    }
211
                } else {
9✔
212
                    // but for now we want to move all of them immediately
3✔
213
                    this._moveToDropdown(newLeftMostItemIndex - this.leftMostItemIndex, 'right');
3✔
214
                    this.ui.dropdown.addClass('cms-more-dropdown-full');
215
                }
216
            } else {
9✔
217
                this._showAllRight();
5✔
218
                this.ui.dropdown.removeClass('cms-more-dropdown-full');
4✔
219
            }
1✔
220
        }
221
    }
222

9✔
223
    /**
224
     * Hides and empties dropdown.
225
     *
226
     * @method _showAll
9✔
227
     * @private
4✔
228
     */
229
    _showAll() {
4✔
230
        this._showAllLeft();
231
        this._showAllRight();
232
        this._hideDropdown();
233
    }
4✔
234

235
    /**
236
     * Show all items in the left part of the toolbar.
237
     *
238
     * @method _showAllLeft
239
     * @private
240
     */
241
    _showAllLeft() {
242
        this._moveOutOfDropdown(this.items.left.length - 1 - this.rightMostItemIndex);
243
    }
244

245
    /**
246
     * Show all items in the right part of the toolbar.
247
     *
4✔
248
     * @method _showAllRight
4✔
249
     * @private
250
     */
251
    _showAllRight() {
5✔
252
        this._moveOutOfDropdown(this.leftMostItemIndex, 'right');
5✔
253
    }
254

255
    /**
256
     * Moves items into the dropdown, reducing menu right-to-left in case it's a left part of toolbar
257
     * and left-to-right if it's right one.
258
     *
259
     * @method _moveToDropdown
260
     * @private
261
     * @param {Number} numberOfItems how many items to move to dropdown
262
     * @param {String} part from which part to move to dropdown (defaults to left)
263
     */
264
    _moveToDropdown(numberOfItems, part) {
10✔
265
        if (numberOfItems <= 0) {
10✔
266
            return;
10✔
267
        }
268

269
        var item;
270
        var leftMostIndexToMove;
271
        var rightMostIndexToMove;
272
        var i;
273

274
        if (part === 'right') {
275
            // Move items (working left-to-right) from the toolbar left part to the more menu.
276
            leftMostIndexToMove = this.leftMostItemIndex;
10✔
277
            rightMostIndexToMove = this.leftMostItemIndex + numberOfItems - 1;
278
            for (i = leftMostIndexToMove; i <= rightMostIndexToMove; i++) {
279
                item = this.items.right[i].element;
280

281
                this.ui.dropdown.prepend(item.wrap('<li class="cms-more-buttons"></li>').parent());
282
            }
283

284
            this.leftMostItemIndex += numberOfItems;
285
        } else {
286
            // Move items (working right-to-left) from the toolbar left part to the more menu.
15✔
287
            rightMostIndexToMove = this.rightMostItemIndex;
288
            leftMostIndexToMove = this.rightMostItemIndex - numberOfItems + 1;
289
            for (i = rightMostIndexToMove; i >= leftMostIndexToMove; i--) {
290
                item = this.items.left[i].element;
291

292
                this.ui.dropdown.prepend(item);
293
                if (item.find('> ul').children().length) {
294
                    item.addClass('cms-toolbar-item-navigation-children');
295
                }
296
            }
297

298
            this.rightMostItemIndex -= numberOfItems;
299
        }
9✔
300
    }
1✔
301

302
    /**
303
     * Moves items out of the dropdown.
304
     *
305
     * @method _moveOutOfDropdown
306
     * @private
307
     * @param {Number} numberOfItems how many items to move out of the dropdown
308
     * @param {String} part to which part to move out of dropdown (defaults to left)
8✔
309
     */
310
    _moveOutOfDropdown(numberOfItems, part) {
3✔
311
        if (numberOfItems <= 0) {
3✔
312
            return;
3✔
313
        }
9✔
314

315
        var i;
9✔
316
        var item;
317
        var leftMostIndexToMove;
318
        var rightMostIndexToMove;
3✔
319

320
        if (part === 'right') {
321
            // Move items (working bottom-to-top) from the more menu into the toolbar right part.
5✔
322
            rightMostIndexToMove = this.leftMostItemIndex - 1;
5✔
323
            leftMostIndexToMove = this.leftMostItemIndex - numberOfItems;
5✔
324

14✔
325
            for (i = rightMostIndexToMove; i >= leftMostIndexToMove; i--) {
326
                item = this.items.right[i].element;
14✔
327
                item.unwrap('<li></li>');
14✔
328

9✔
329
                item.prependTo(this.ui.toolbarRightPart);
330
            }
331

332
            this.leftMostItemIndex -= numberOfItems;
5✔
333
        } else {
334
            // Move items (working top-to-bottom) from the more menu into the toolbar left part.
335
            leftMostIndexToMove = this.rightMostItemIndex + 1;
336
            rightMostIndexToMove = this.rightMostItemIndex + numberOfItems;
337

338
            for (i = leftMostIndexToMove; i <= rightMostIndexToMove; i++) {
339
                item = this.items.left[i].element;
340

341
                item.insertBefore(this.ui.trigger);
342
                item.removeClass('cms-toolbar-item-navigation-children');
343
                item.find('> ul').removeAttr('style');
344
            }
345

26✔
346
            this.rightMostItemIndex += numberOfItems;
24✔
347
        }
348
    }
349
}
350

351
export default Navigation;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc