PageSourceSearch

https://www.0532.ua/assets/2851b084/itemsListArranger.js?v=1789825604

js 0532.ua collected 2026-10-02 10:23:52 UTC 16,286 bytes, 349 lines download raw bytes

1(function ($) {
2    $.fn.itemsListArranger = function (option) {
3
4        var ItemsListArranger = function (element, options) {
5            this.settings = $.extend({}, ItemsListArranger.defaultOptions, options);
6
7            this.$container = $(element);
8            this.hideIncompleteRow = this.settings.hideIncompleteRow;
9            this.columnsCount = -1;
10            this.linkedList = {
11                $prev: this.settings.linkedList.prev ? $(this.settings.linkedList.prev) : null,
12                $next: this.settings.linkedList.next ? $(this.settings.linkedList.next) : null
13            };
14            this._initEventHandlers();
15            this._checkHideIncompleteRowMode();
16            if (this.settings.arrangeOnInit) {
17                var columnsCount = this._updateColumnsCount();
18                if (this.columnsCount !== columnsCount) {
19                    this.columnsCount = columnsCount;
20                    this.$container.trigger("columnsCountChanged", this.columnsCount);
21                }
22            }
23        };
24
25        ItemsListArranger.namespace = "itemsListArranger";
26
27        ItemsListArranger.defaultOptions = {
28            itemsSelector: "div.item",
29            singleBlockSelector: ".item-single-block",
30            doubleBlockSelector: ".item-double-block",
31            mustBeDoubleSelector: ".item-must-be-double",
32            doSingleBlock: $.noop,
33            doDoubleBlock: $.noop,
34            hideIncompleteRow: true,
35            arrangeOnInit: true,
36            // Поддержка подгрузки данных при помощи AJAX'а
37            hookPageDataLoadedEvent: true,
38            pageDataLoadedEvent: "newPageDataLoaded",
39            moreButtonSelector: ".btn.loader",
40            // Обработчики событий
41            beforeListArrange: null,
42            afterListArrange: null,
43            columnsCountChanged: null,
44            linkedList: {
45                prev: null,
46                next: null
47            },
48            minimalRows: 1
49        };
50
51        ItemsListArranger.prototype._updateColumnsCount = function () {
52            var containerWidth = this.$container.innerWidth(),
53                $block = $(this.settings.singleBlockSelector, this.$container).first(),
54                blockWidth = 0;
55
56            // Определяем ширину блока и количество колонок
57            if ($block.length > 0) {
58                blockWidth = $block.outerWidth(true);
59            } else {
60                $block = $(this.settings.doubleBlockSelector, this.$container).first();
61                if ($block.length > 0) {
62                    blockWidth = $block.outerWidth(true) / 2.0;
63                }
64            }
65            if (0 === blockWidth) return -1;
66            // Константу 0.3 используем для более прогнозируемого результата
67            var columnsCount = Math.floor(containerWidth / blockWidth + 0.3);
68            return 0 !== columnsCount ? columnsCount : -1;
69        };
70
71        ItemsListArranger.prototype._internalDoSingleBlock = function ($block) {
72            switch (typeof this.settings.doSingleBlock) {
73                case "function":
74                    $.proxy(this.settings.doSingleBlock, this)($block);
75                    break;
76                case "string":
77                    // doSingleBlock - перечень добавляемых классов
78                    if (typeof this.settings.doDoubleBlock === "string") {
79                        $block.removeClass(this.settings.doDoubleBlock);
80                    }
81                    $block.addClass(this.settings.doSingleBlock);
82                    break;
83            }
84        };
85
86        ItemsListArranger.prototype._internalDoDoubleBlock = function ($block) {
87            switch (typeof this.settings.doDoubleBlock) {
88                case "function":
89                    $.proxy(this.settings.doDoubleBlock, this)($block);
90                    break;
91                case "string":
92                    // doDoubleBlock - перечень добавляемых классов
93                    if (typeof this.settings.doSingleBlock === "string") {
94                        $block.removeClass(this.settings.doSingleBlock);
95                    }
96                    $block.addClass(this.settings.doDoubleBlock);
97                    break;
98            }
99        };
100
101        ItemsListArranger.prototype._checkHideIncompleteRowMode = function () {
102            /*
103             * Если отсутствует кнопка "Еще" и событие загрузки новых данных обрабатывается,
104             * то отключаем "скрывание" незавершенных рядов
105             */
106            var settings = this.settings,
107                $loadMoreButton = $(settings.moreButtonSelector, this.$container),
108                overrideHideIncompleteRow = settings.hookPageDataLoadedEvent && $loadMoreButton.length === 0;
109            this.hideIncompleteRow = !overrideHideIncompleteRow ? this.settings.hideIncompleteRow : false;
110        };
111
112        ItemsListArranger.prototype._arrangeItems = function () {
113            var self = this,
114                settings = this.settings,
115                columnsCount = this.columnsCount,
116                actualColumn = 0,
117                itemsInRow = 0,
118                realItemsInRow = 0,
119                extraItemsCount = 0,
120                rowsCount = 0,
121                $items = this.getItems();
122            if (0 === $items.length && null !== this.linkedList.$next && 1 === this.linkedList.$next.length) {
123                this.$container.append($.map(
124                    self.linkedList.$next.itemsListArranger("shiftItems", self.columnsCount * self.settings.minimalRows),
125                    function (item) {
126                        self._internalDoSingleBlock($(item));
127                        return $(item);
128                    }
129                ));
130                $items = this.getItems();
131            }
132
133            this.$container.trigger("beforeListArrange");
134            var delta = Date.now();
135
136            // Перебираем все элементы списка
137            $items.each(function (index, element) {
138                if (0 === itemsInRow) {
139                    realItemsInRow = 0;
140                }
141                if (rowsCount >= settings.minimalRows) {
142                    ++extraItemsCount;
143                }
144                var $item = $(this),
145                    canBlockExpand = self._canBlockExpand(actualColumn, columnsCount);
146                if ($item.is(":hidden")) {
147                    $item.show();
148                }
149                if ($item.is(settings.doubleBlockSelector)) {
150                    // Двойной блок
151                    if (!canBlockExpand) {
152                        self._internalDoSingleBlock($item);
153                    }
154                } else {
155                    // Одинарный блок
156                    if ($item.is(settings.mustBeDoubleSelector) && canBlockExpand) {
157                        self._internalDoDoubleBlock($item);
158                    }
159                }
160                var blockWidth = $item.is(settings.doubleBlockSelector) ? 2 : 1;
161                actualColumn = (actualColumn + blockWidth) % columnsCount;
162                // Количество элементов в текущей строке
163                itemsInRow = 0 === actualColumn ? 0 : (itemsInRow + 1);
164                if (0 === itemsInRow) {
165                    ++rowsCount;
166                }
167                ++realItemsInRow;
168            });
169            // Скрываем ряды, которые заполненны не полностью
170            var isRowComplete = 0 === itemsInRow;
171            if (!isRowComplete) {
172                if (this.hideIncompleteRow) {
173                    var $itemsToHide = $items.slice(-itemsInRow);
174                    $itemsToHide.hide();
175                    // Если отсутствуют видимые элементы, то отображаем то, что есть
176                    if ($items.filter(":visible").length === 0) {
177                        $items.show();
178                    }
179                }/* else if (null !== this.linkedList.$next) {
180                    //if (itemsInRow > columnsCount / 2) {
181                    if (rowsCount < settings.minimalRows) {
182                        this.$container.append(
183                            $.map(this.linkedList.$next.itemsListArranger("shiftItems", columnsCount - itemsInRow), function (item) {
184                                self._internalDoSingleBlock($(item));
185                                return $(item);
186                            })
187                        );
188                    } else {
189                        this.linkedList.$next.itemsListArranger("unshiftItems", $itemsToHide);
190                    }
191                }*/
192            }
193            if (null !== this.linkedList.$next) {
194                if (rowsCount !== settings.minimalRows || !isRowComplete) {
195                    var itemsCount;
196                    //itemsInRow = 0 !== itemsInRow ? itemsInRow : columnsCount;
197                    if (rowsCount < settings.minimalRows) {
198                        itemsCount = settings.minimalRows * columnsCount - $items.length;
199                        this.$container.append($.map(
200                            this.linkedList.$next.itemsListArranger("shiftItems", itemsCount),
201                            function (item) {
202                                self._internalDoSingleBlock($(item));
203                                return $(item);
204                            }
205                        ));
206                        this._arrangeItems();
207                    } else {
208                        itemsCount = extraItemsCount;
209                        this.linkedList.$next.itemsListArranger("unshiftItems", $items.slice(-itemsCount));
210                    }
211                }
212            }
213
214            this.$container.trigger("afterListArrange");
215            /*
216            console.log(this.$container.prop("id") + ": arrange in " + (Date.now() - delta) + " ms, " +
217                columnsCount + " columns ");
218            */
219        };
220
221        ItemsListArranger.prototype._canBlockExpand = function (blockColumn, columnsCount, exp
221andWidth) {
222            expandWidth = expandWidth || 2;
223            return (blockColumn + expandWidth - 1) < columnsCount;
224        };
225
226        ItemsListArranger.prototype._initEventHandlers = function () {
227            var self = this,
228                settings = this.settings;
229            $(window).on("resize." + ItemsListArranger.namespace, function (event) {
230                if (null !== self.linkedList.$prev) {
231                    return;
232                }
233                var columnsCount = self._updateColumnsCount();
234                if (self.columnsCount !== columnsCount) {
235                    self.columnsCount = columnsCount;
236                    self.$container.trigger("columnsCountChanged", this.columnsCount);
237                }
238            });
239            if (settings.hookPageDataLoadedEvent) {
240                var eventName = settings.pageDataLoadedEvent + '.' + ItemsListArranger.namespace;
241                this.$container.on(eventName, function (event, $newItems) {
242                    self._checkHideIncompleteRowMode();
243                    self._arrangeItems();
244                });
245            }
246            if (null !== self.linkedList.$prev) {
247                self.linkedList.$prev.on("afterListArrange", function (event) {
248                    var columnsCount = self._updateColumnsCount();
249                    if (self.columnsCount !== columnsCount) {
250                        self.columnsCount = columnsCount;
251                        self.$container.trigger("columnsCountChanged", this.columnsCount);
252                    }
253                });
254            }
255            this.$container
256                .on("beforeListArrange." + ItemsListArranger.namespace, function (event) {
257                    if (typeof settings.beforeListArrange === "function") {
258                        $.proxy(settings.beforeListArrange, self)();
259                    }
260                })
261                .on("afterListArrange." + ItemsListArranger.namespace, function (event) {
262                    if (typeof settings.afterListArrange === "function") {
263                        $.proxy(settings.afterListArrange, self)();
264                    }
265                })
266                .on("columnsCountChanged." + ItemsListArranger.namespace, function (event, newColumnCount) {
267                    self._arrangeItems();
268                    if (typeof settings.columnsCountChanged === "function") {
269                        $.proxy(settings.columnsCountChanged, self)(newColumnCount);
270                    }
271                });
272        };
273
274        ItemsListArranger.prototype.getItems = function () {
275            return $(this.settings.itemsSelector, this.$container);
276        };
277
278        ItemsListArranger.prototype.shiftItems = function (count) {
279            var self = this,
280                items = this.getItems().splice(0, count);
281            $.each(items, function (index, item) {
282                $(item).detach();
283            });
284            if (count > items.length && null !== this.linkedList.$next && 1 === this.linkedList.$next.length) {
285                items = items.concat(this.linkedList.$next.itemsListArranger("shiftItems", count - items.length));
286            }
287            if (null !== this.linkedList.$next && 1 === this.linkedList.$next.length) {
288                this.$container.append($.map(
289                    self.linkedList.$next.itemsListArranger("shiftItems", Math.min(count, self.columnsCount * self.settings.minimalRows)),
290                    function (item) {
291                        self._internalDoSingleBlock($(item));
292                        return $(item);
293                    }
294                ));
295            }
296
297            return items;
298        };
299
300        ItemsListArranger.prototype.unshiftItems = function (items) {
301            if (0 === items.length) {
302                return;
303            }
304            var self = this,
305                containerItems = this.getItems();
306            if (null !== this.linkedList.$next) {
307                var itemsToInsert = items.length >= containerItems.length ?
308                    items.splice(items.length - containerItems.length).concat(containerItems) :
309                    containerItems.splice(-items.length);
310                $.each(itemsToInsert, function (index, item) {
311                    $(item).detach();
312                });
313                this.linkedList.$next.itemsListArranger("unshiftItems", itemsToInsert);
314            }
315            this.$container.prepend($.map(items, function (item) {
316                self._internalDoSingleBlock($(item));
317                return $(item);
318            }));
319        };
320
321        ItemsListArranger.methods = {
322            update: ItemsListArranger.prototype._updateColumnsCount,
323            getItems: ItemsListArranger.prototype.getItems,
324            shiftItems: ItemsListArranger.prototype.shiftItems,
325            unshiftItems: ItemsListArranger.prototype.unshiftItems
326        };
327
328        var scopeArguments = arguments;
329        if ("string" === typeof option && "function" === typeof ItemsListArranger.methods[option]) {
330            var data = this.data("cis." + ItemsListArranger.namespace);
331            if (data) {
332                return ItemsListArranger.methods[option].apply(data, Array.prototype.slice.call(scopeArguments, 1));
333            }
334        }
335        return this.each(function (index, element) {
336            var $this = $(this);
337            var data = $this.data("cis." + ItemsListArranger.namespace);
338            var options = "object" === typeof option && option;
339
340            if (!data) {
341                $this.data("cis." + ItemsListArranger.namespace, (data = new ItemsListArranger(this, options)));
342            }
343            if ("string" === typeof option && "function" === typeof ItemsListArranger.methods[option]) {
344                ItemsListArranger.methods[option].apply(data, Array.prototype.slice.call(scopeArguments, 1));
345            }
346        });
347
348    };
349})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.