PageSourceSearch

https://smartrivas.com/wp-content/themes/soledad/inc/woocommerce/js/jquery-grid-picker.js?ver=8.7.6

js smartrivas.com collected 2026-10-06 19:32:16 UTC 19,455 bytes, 625 lines download raw bytes

1;(function (root, factory) {
2    // AMD.
3    if (typeof define === "function" && define.amd)
4        define(["jquery"], factory);
5
6    // Node, CommonJS-like.
7    else if (typeof exports === "object")
8        factory(require("jquery"));
9
10    // Browser globals.
11    else
12        factory(root.jQuery);
13}(this, function ($) {
14    // Strict mode.
15    "use strict";
16
17    // @todo
18    //      - markup: datalist > option
19    //      - markup: select > optgroup > option
20
21    /**
22     * Initialize GridPicker.
23     *
24     * @param  {HTMLSelectElement} element select element node
25     * @param  {Object}            options see GridPicker.prototype._defaults
26     * @return {Void}
27     */
28    var GridPicker = function (element, options) {
29        if (!(this instanceof GridPicker))
30            throw "GridPicker: GridPicker is a constructor.";
31        if (!(element instanceof HTMLSelectElement))
32            throw "GridPicker: element argument must be of type HTMLSelectElement.";
33
34        this._element = element;
35        this._options = options;
36
37        this._init();
38    }
39
40    /**
41     * GridPicker prototype.
42     *
43     * @type {Object}
44     */
45    GridPicker.prototype = {
46        /**
47         * Default options.
48         *
49         * @type {Object}
50         */
51        _defaults: {
52            /**
53             * Render method.
54             *
55             * If not defined (Null) the default render
56             * method will be used. The first argument
57             * in function is HTMLOptionElement, and the
58             * result should be any HTMLElement.
59             *
60             * Example usage:
61             *
62             * $(selector).gridPicker({
63             *     render: function(element) {
64             *         return $("<a />")
65             *             .attr("href", "#")
66             *             .attr("title", label)
67             *             .text(label)
68             *             .get(0);
69             *     }
70             * }
71             *
72             * @type {Function|Null}
73             */
74            render: null,
75
76            /**
77             * Can item be selected.
78             *
79             * If not defined (Null) the default canSelect
80             * method will be used. It can be True, False
81             * or Function. The first argument in function
82             * is HTMLOptionElement, and the result should
83             * be True|False.
84             *
85             * Example usage:
86             *
87             * $(selector).gridPicker({
88             *     canSelect: function(element) {
89             *         return !$(element).is(":disabled");
90             *     }
91             * }
92             *
93             * @type {Function|Boolean|Null}
94             */
95            canSelect: null,
96
97            /**
98             * Can item be unselected.
99             *
100             * If not defined (Null) the default canUnselect
101             * method will be used. It can be True, False
102             * or Function. The first argument in function
103             * is HTMLOptionElement, and the result should
104             * be True|False.
105             *
106             * Example usage:
107             *
108             * $(selector).gridPicker({
109             *     canUnselect: function(element) {
110             *         return typeof this._$ui.element.attr("multiple") !== "undefined";
111             *     }
112             * }
113             *
114             * @type {Function|Boolean|Null}
115             */
116            canUnselect: null,
117        },
118
119        /**
120         * Constructor.
121         *
122         * @return {Void}
123         */
124        _init: function () {
125            // Already instanced.
126            if ($(this._element).data("jquery-grid-picker"))
127                return;
128
129            // Init all.
130            this._initElement();
131            this._initWidget();
132            this._initOptions();
133            this._initUi();
134            this._initObserver();
135
136            // Render items.
137            this.refresh();
138        },
139
140        /**
141         * Initialize element.
142         *
143         * @return {Void}
144         */
145        _initElement: function () {
146            this._element = $(this._element)
147                .addClass("jquery-grid-picker")
148                .off(".jquerygridpicker")
149                .on("change.jquerygridpicker", this._handleElementChange.bind(this))
150                .data("jquery-grid-picker", this)
151                .get(0);
152        },
153
154        /**
155         * Initialize widget.
156         *
157         * @return {Void}
158         */
159        _initWidget: function () {
160            this._widget = $("<ul />")
161                .addClass("jquery-grid-picker-widget")
162                .on("click.jquerygridpicker", ".jquery-grid-picker-item", this._handleItem
162Click.bind(this))
163                .insertAfter(this.element)
164                .get(0);
165        },
166
167        /**
168         * Initialize options.
169         *
170         * @return {Void}
171         */
172        _initOptions: function () {
173            this._options = $.extend({}, this._defaults, this._options);
174
175            // Delete invalid option keys.
176            for (var key in this._options) {
177                if (!this._defaults.hasOwnProperty(key))
178                    delete this._options[key];
179            }
180        },
181
182        /**
183         * Initialize ui.
184         *
185         * @return {Void}
186         */
187        _initUi: function () {
188            this._$ui = {
189                element: $(this.element),
190                widget: $(this.widget),
191                items: $(null),
192            };
193        },
194
195        /**
196         * Initialize mutation observer.
197         *
198         * @return {Void}
199         */
200        _initObserver: function () {
201            this._observer = null;
202            if (typeof MutationObserver === "undefined")
203                return;
204
205            this._observer = new MutationObserver(this._handleMutation.bind(this));
206            this._observer.observe(this.element, {
207                attributes: true,
208                childList: true,
209                subtree: true,
210                characterData: true,
211            });
212        },
213
214        /**
215         * Destructor.
216         *
217         * @return {Void}
218         */
219        destroy: function () {
220            if (this._observer)
221                this._observer.disconnect();
222
223            this._$ui.element
224                .off(".jquerygridpicker")
225                .removeClass("jquery-grid-picker")
226                .removeData("jquery-grid-picker");
227            this._$ui.widget
228                .remove();
229
230            this._$ui = null;
231            this._observer = null;
232            this._options = null;
233            this._widget = null;
234            this._element = null;
235        },
236
237        /**
238         * Element property getter.
239         *
240         * @return {HTMLSelectElement}
241         */
242        get element() {
243            return this._element;
244        },
245
246        /**
247         * Widget property getter.
248         *
249         * @return {HTMLElement}
250         */
251        get widget() {
252            return this._widget;
253        },
254
255        /**
256         * Get option.
257         *
258         * @param  {String} key
259         * @return {Mixed}
260         */
261        getOption: function (key) {
262            return this._options[key];
263        },
264
265        /**
266         * Set option.
267         *
268         * @param  {String} key
269         * @param  {Mixed}  value
270         * @return {Void}
271         */
272        setOption: function (key, value) {
273            if (this._defaults.hasOwnProperty(key))
274                this._options[key] = value;
275        },
276
277        /**
278         * Element value.
279         *
280         * @return {String}
281         */
282        value: function () {
283            return this._$ui.element.val();
284        },
285
286        /**
287         * Reset element value to null.
288         *
289         * @return {Void}
290         */
291        reset: function () {
292            this._$ui.element.val(null);
293        },
294
295        /**
296         * Refresh (render) option list.
297         *
298         * @return {Void}
299         */
300        refresh: function () {
301            this._$ui.widget.empty();
302            this._$ui.items = $(null);
303
304            this._$ui.element
305                .find("option")
306                .each(function (index, element) {
307                    this._syncItem(element);
308                }.bind(this));
309
310            this._handleElementChange();
311        },
312
313        /**
314         * Sync select option and widget list item.
315         *
316         * @param  {HTMLOptionElement} element
317         * @return {Void}
318         */
319        _syncItem: function (element) {
320            // Clear old element widget item (if exists).
321            var $element = $(element),
322                attached = !!$element.closest(this.element).length,
323                value = $element.val(),
324                item = this._$ui.items.filter('[data-jquery-grid-picker-value="' + this._selectorEscape(value) + '"]').get(0);
325            this._$ui.items = this._$ui.items.not(item);
326            $(item).remove();
327
328            // Element is detached, nothing else to do here.
329            if (!attached)
330                return;
331
332            // Render item content from render option.
333            var content = null,
334                render = this.getOption("render");
335            if (typeof render === "function")
336                content = render.call(this, element);
337            else
338                content = this._renderItemContent(element);
339            if (!content)
340                return;
341
342            var index = $element.index(),
343                selected = $element.prop("selected"),
344                hidden = $element.css("display") === "none",
345                disabled = $element.is(":disabled");
346
347            // Render new element widget item.
348            item = this._renderItemWrapper(element);
349            $(item)
350                .addClass("jquery-grid-picker-item")
351                .addClass("jquery-grid-picker-item-" + (selected ? "selected" : "temp"))
352                .addClass("jquery-grid-picker-item-" + (hidden ? "hidden" : "temp"))
353                .addClass("jquery-grid-picker-item-" + (disabled ? "disabled" : "temp"))
354                .removeClass("jquery-grid-picker-item-temp")
355                .attr("data-jquery-grid-picker-value", value)
356                .removeAttr("data-jquery-grid-picker-item-temp");
357            $(content)
358                .addClass("jquery-grid-picker-item-content")
359                .appendTo(item);
360
361            // ...and append it to widget.
362            if (!index)
363                this._$ui.widget.prepend(item);
364            else
365                this._$ui.widget.find(".jquery-grid-picker-item:nth-child(" + index + ")").after(item);
366
367            // Refresh ui.
368            this._$ui.items = this._$ui.items
369                .add(item);
370        },
371
372        /**
373         * Render list item wrapper.
374         *
375         * @param  {HTMLOptionElement} element
376         * @return {HTMLElement}
377         */
378        _renderItemWrapper: function (element) {
379            return $("<li />").get(0);
380        },
381
382        /**
383         * Render list item (default) content:
384         * this is a render fallback if no render
385         * option is specified.
386         *
387         * @param  {HTMLOptionElement} element
388         * @return {HTMLElement}
389         */
390        _renderItemContent: function (element) {
391            var $element = $(element),
392                label = $element.attr("label") || $element.text();
393            return $("<a />")
394                .attr("href", "#")
395                .attr("title", label)
396                .attr("data-tippy-content", label)
397                .attr("draggable", "false")
398                .text(label)
399                .get(0);
400        },
401
402        /**
403         * Can select item.
404         *
405         * @param  {HTMLOptionElement} element
406         * @return {Boolean}
407         */
408        _canSelect: function (element) {
409            var option = this.getOption("canSelect");
410            if (typeof option === "boolean")
411                return option;
412            else if (typeof option === "function")
413                return !!option.call(this, element);
414
415            return !$(element).is(":disabled");
416        },
417
418        /**
419         * Can unselect item.
420         *
421         * @param  {HTMLOptionElement} element
422         * @return {Boolean}
423         */
424        _canUnselect: function (element) {
425            var option = this.getOption("canUnselect");
426            if (typeof option === "boolean")
427                return option;
428            else if (typeof option === "function")
429                return !!option.call(this, element);
430
431            return this.element.hasAttribute("multiple");
432        },
433
434        /**
435         * Escape string so we can use it as css selector.
436         *
437         * @param  {String} str
438         * @return {String}
439         */
440        _selectorEscape: function (str) {
441            return str.toString()
442                .replace(/"/g, "\\\"");
443        },
444
445        /**
446         * Mutation observer callback:
447         * sync select option and widget list item.
448         *
449         * @param  {Array} e
450         * @return {Void}
451         */
452        _handleMutation: function (e) {
453            // Element list that needs sync. It would be easier
454            // to use jQuery object here, but jQuery's list of
455            // elements is sorted. We need to apply sync method
456            // on elements as provided in MutationRecord list.
457            var elements = [],
458                addToElements = function (element) {
459                    $(element)
460                        .closest("option")
461                        .each(function (index, value) {
462                            if (elements.indexOf(value) === -1)
463                                elements.push(value);
464                        });
465                };
466
467            // Iterate mutation record list and find elements
468            // that need sync.
469            e.forEach(function (record) {
470                if (record.type === "childList") {
471                    addToElements(record.removedNodes);
472                    addToElements(record.addedNodes);
473                } else if ((record.type === "attributes" && record.target !== this.element) || (record.type === "characterData"))
474                    addToElements(record.target);
475            }.bind(this));
476
477            // Sync mutated elements.
478            elements.forEach(function (element) {
479                this._syncItem(element);
480            }.bind(this));
481        },
482
483        /**
484         * Element change event handler.
485         *
486         * @param  {Event} e
487         * @return {Void}
488         */
489        _handleElementChange: function (e) {
490            var value = this.value(),
491                filter = null;
492
493            if (typeof value === "string")
494                filter = '[data-jquery-grid-picker-value="' + this._selectorEscape(value) + '"]';
495            else if (value instanceof Array)
496                filter = value
497                    .map(function (item) {
498                        return '[data-jquery-grid-picker-value="' + this._selectorEscape(item) + '"]';
499                    }.bind(this))
500                    .join(",");
501
502            this._$ui.items
503                .removeClass("jquery-grid-picker-item-selected")
504                .filter(filter)
505                .addClass("jquery-grid-picker-item-selected");
506        },
507
508        /**
509         * Item click event handler.
510         *
511         * @param  {Event} e
512         * @return {Void}
513         */
514        _handleItemClick: function (e) {
515            e.preventDefault();
516
517            var target = e.currentTarget,
518                value = $(target).attr("data-jquery-grid-picker-value") || "",
519                $option = this._$ui.element.find('option[value="' + this._selectorEscape(value) + '"]'),
520                option = $option.get(0),
521                isSelected = $option.is(":selected");
522
523            // Unselect selected.
524            if (isSelected && this._canUnselect(option)) {
525                // Non multiple select elements can not have all the
526                // options unselected (it will default to first option),
527                // so we will reset it's value.
528                var length = this._$ui.element.find("option:selected").length;
529                if (length - 1 === 0)
530                    this.reset();
531                else
532                    $option.prop("selected", false);
533            }
534
535            // Select unselected.
536            else if (!isSelected && this._canSelect(option))
537                $option.prop("selected", true);
538
539            // Select/unselect fail, return.
540            else
541                return;
542
543            // Trigger change and let change event handler
544            // do the rest.
545            this._$ui.element
546                .trigger("change");
547        },
548    };
549
550    // Re-assign constuctor.
551    GridPicker.prototype.constructor = GridPicker;
552
553    /**
554     * jQuery gridPicker plugin:
555     * display HTMLSelectElement as grid with clickable
556     * (select/unselect) items.
557     *
558     * Instance new GridPicker on element(s)
559     * >> $(selector).gridPicker(options);
560     *
561     * ...execute GridPicker method
562     * >> $(selector)
563     *        .gridPicker("setOption", "canUnselect", true)
564     *        .gridPicker("reset");
565     *
566     * ...or access GridPicker property
567     * >> var widget = $(selector).gridPicker("widget");
568     *
569     * @param  {Mixed} options
570     * @return {Mixed}
571     */
572    $.fn.gridPicker = function (options) {
573        var classObject = GridPicker,
574            className = "GridPicker",
575            store = "jquery-grid-picker",
576            args = Array.prototype.slice.call(arguments, 1),
577            $this = $(this);
578
579        // Iterate all
580        $this.each(function () {
581            // Get instance (or create new one).
582            var instance = $(this).data(store);
583            if (!instance)
584                instance = new classObject(this, typeof options === "object" ? options : {});
585
586            // Access properties.
587            if (typeof options === "string") {
588                var exists = options in instance,
589                    isPrivate = options.substr(0, 1) === "_",
590                    type = typeof instance[options];
591
592                // Property is function, execute it.
593                if (exists && !isPrivate && type === "function" && instance[options] !== Object.prototype[options] && options !== "constructor") {
594                    var result = instance[options].apply(instance, args);
595
596                    // Function returned result (non undefined), store
597                    // result, exit loop.
598                    if (typeof result !== "undefined") {
599                        $this = result;
600                        return false;
601                    }
602                }
603
604                // Property as getter (get, store result, exit loop).
605                else if (exists && !isPrivate && type !== "function" && !args.length) {
606                    $this = instance[options];
607                    return false;
608                }
609
610                // Property as setter (set, continue).
611                else if (exists && !isPrivate && type !== "function") {
612                    instance[options] = args[0];
613                }
614
615                // Invalid option argument.
616                else {
617                    throw className + ": " + options + " is not a valid " + className + " property.";
618                }
619            }
620        });
621
622        // ...finally.
623        return $this;
624    };
625}));

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.