UNPKG

@coreui/coreui-pro

Version:

The most popular front-end framework for developing responsive, mobile-first projects on the web rewritten by the CoreUI Team

466 lines (439 loc) 18.8 kB
/*! * CoreUI rating.js v5.14.2 (https://coreui.io) * Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people) * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE) */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./util/sanitizer.js'), require('./util/index.js'), require('./tooltip.js')) : typeof define === 'function' && define.amd ? define(['exports', './base-component', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './util/sanitizer', './util/index', './tooltip'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Rating = {}, global.BaseComponent, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Sanitizer, global.Index, global.Tooltip)); })(this, (function (exports, BaseComponent, EventHandler, Manipulator, SelectorEngine, sanitizer_js, index_js, Tooltip) { 'use strict'; /** * -------------------------------------------------------------------------- * CoreUI PRO rating.js * License (https://coreui.io/pro/license/) * -------------------------------------------------------------------------- */ /** * Constants */ const NAME = 'rating'; const DATA_KEY = 'coreui.rating'; const EVENT_KEY = `.${DATA_KEY}`; const DATA_API_KEY = '.data-api'; const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']); const EVENT_CHANGE = `change${EVENT_KEY}`; const EVENT_CLICK = `click${EVENT_KEY}`; const EVENT_FOCUSIN = `focusin${EVENT_KEY}`; const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`; const EVENT_HOVER = `hover${EVENT_KEY}`; const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`; const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`; const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`; const CLASS_NAME_ACTIVE = 'active'; const CLASS_NAME_DISABLED = 'disabled'; const CLASS_NAME_RATING = 'rating'; const CLASS_NAME_RATING_ITEM = 'rating-item'; const CLASS_NAME_RATING_ITEM_ICON = 'rating-item-icon'; const CLASS_NAME_RATING_ITEM_CUSTOM_ICON = 'rating-item-custom-icon'; const CLASS_NAME_RATING_ITEM_CUSTOM_ICON_ACTIVE = 'rating-item-custom-icon-active'; const CLASS_NAME_RATING_ITEM_INPUT = 'rating-item-input'; const CLASS_NAME_RATING_ITEM_LABEL = 'rating-item-label'; const CLASS_NAME_READONLY = 'readonly'; const SELECTOR_DATA_TOGGLE = '[data-coreui-toggle="rating"]'; const SELECTOR_RATING_ITEM_INPUT = '.rating-item-input'; const SELECTOR_RATING_ITEM_LABEL = '.rating-item-label'; // js-docs-start svg-allow-list const svgAllowList = { ...sanitizer_js.DefaultAllowlist, svg: ['xmlns', 'version', 'baseprofile', 'width', 'height', 'viewbox', 'preserveaspectratio', 'aria-hidden', 'role', 'focusable'], g: ['id', 'class', 'transform', 'style'], path: ['id', 'class', 'd', 'fill', 'fill-opacity', 'fill-rule', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-opacity'], circle: ['id', 'class', 'cx', 'cy', 'r', 'fill', 'fill-opacity', 'stroke', 'stroke-width', 'stroke-opacity'], rect: ['id', 'class', 'x', 'y', 'width', 'height', 'rx', 'ry', 'fill', 'fill-opacity', 'stroke', 'stroke-width', 'stroke-opacity'], ellipse: ['id', 'class', 'cx', 'cy', 'rx', 'ry', 'fill', 'fill-opacity', 'stroke', 'stroke-width', 'stroke-opacity'], line: ['id', 'class', 'x1', 'y1', 'x2', 'y2', 'stroke', 'stroke-width', 'stroke-opacity'], polygon: ['id', 'class', 'points', 'fill', 'fill-opacity', 'stroke', 'stroke-width', 'stroke-opacity'], polyline: ['id', 'class', 'points', 'fill', 'fill-opacity', 'stroke', 'stroke-width', 'stroke-opacity'], text: ['id', 'class', 'x', 'y', 'dx', 'dy', 'text-anchor', 'font-family', 'font-size', 'font-weight', 'fill', 'fill-opacity', 'stroke', 'stroke-width', 'stroke-opacity'], tspan: ['id', 'class', 'x', 'y', 'dx', 'dy', 'text-anchor', 'font-family', 'font-size', 'font-weight', 'fill', 'fill-opacity', 'stroke', 'stroke-width', 'stroke-opacity'], defs: [], symbol: ['id', 'class', 'viewbox', 'preserveaspectratio'], use: ['id', 'class', 'x', 'y', 'width', 'height', 'href'], image: ['id', 'class', 'x', 'y', 'width', 'height', 'href', 'preserveaspectratio', 'xlink:href'], pattern: ['id', 'class', 'x', 'y', 'width', 'height', 'patternunits', 'patterncontentunits', 'patterntransform', 'preserveaspectratio'], lineargradient: ['id', 'class', 'gradientunits', 'x1', 'y1', 'x2', 'y2', 'spreadmethod', 'gradienttransform'], radialgradient: ['id', 'class', 'gradientunits', 'cx', 'cy', 'r', 'fx', 'fy', 'spreadmethod', 'gradienttransform'], mask: ['id', 'class', 'x', 'y', 'width', 'height', 'maskunits', 'maskcontentunits', 'masktransform'], clippath: ['id', 'class', 'clippathunits'], marker: ['id', 'class', 'markerunits', 'markerwidth', 'markerheight', 'orient', 'preserveaspectratio', 'viewbox', 'refx', 'refy'], title: [], desc: [] }; // js-docs-end svg-allow-list const Default = { activeIcon: null, allowClear: false, allowList: svgAllowList, disabled: false, highlightOnlySelected: false, icon: null, itemCount: 5, name: null, precision: 1, readOnly: false, sanitizeFn: null, size: null, tooltips: false, value: null }; const DefaultType = { activeIcon: '(object|string|null)', allowClear: 'boolean', allowList: 'object', disabled: 'boolean', highlightOnlySelected: 'boolean', icon: '(object|string|null)', itemCount: 'number', name: '(string|null)', precision: 'number', readOnly: 'boolean', sanitizeFn: '(null|function)', size: '(string|null)', tooltips: '(array|boolean|object)', value: '(number|null)' }; /** * Class definition */ class Rating extends BaseComponent { constructor(element, config) { super(element); this._config = this._getConfig(config); this._currentValue = this._config.value; this._name = this._config.name || index_js.getUID(`${this.constructor.NAME}-name-`).toString(); this._tooltip = null; this._createRating(); this._addEventListeners(); } // Getters static get Default() { return Default; } static get DefaultType() { return DefaultType; } static get NAME() { return NAME; } // Public update(config) { this._config = this._getConfig(config); this._currentValue = this._config.value; this._element.innerHTML = ''; this._createRating(); this._addEventListeners(); } reset(value = null) { this._currentValue = value; this._element.innerHTML = ''; this._createRating(); this._addEventListeners(); EventHandler.trigger(this._element, EVENT_CHANGE, { value }); } // Private _addEventListeners() { EventHandler.on(this._element, EVENT_CLICK, SELECTOR_RATING_ITEM_INPUT, ({ target }) => { if (this._config.disabled || this._config.readOnly) { return; } // eslint-disable-next-line eqeqeq if (this._config.allowClear && this._currentValue == target.value) { this._currentValue = null; target.checked = false; this._resetLabels(); EventHandler.trigger(this._element, EVENT_CHANGE, { value: null }); } }); EventHandler.on(this._element, EVENT_CHANGE, SELECTOR_RATING_ITEM_INPUT, ({ target }) => { if (this._config.disabled || this._config.readOnly) { return; } this._currentValue = target.value; EventHandler.trigger(this._element, EVENT_CHANGE, { value: target.value }); const inputs = SelectorEngine.find(SELECTOR_RATING_ITEM_INPUT, this._element); this._resetLabels(); if (this._config.highlightOnlySelected) { const label = SelectorEngine.findOne(SELECTOR_RATING_ITEM_LABEL, target.parentElement); label.classList.add(CLASS_NAME_ACTIVE); return; } for (const input of inputs) { const label = SelectorEngine.findOne(SELECTOR_RATING_ITEM_LABEL, input.parentElement); label.classList.add(CLASS_NAME_ACTIVE); if (input === target) { break; } } }); EventHandler.on(this._element, EVENT_MOUSEENTER, SELECTOR_RATING_ITEM_LABEL, ({ target }) => { if (this._config.disabled || this._config.readOnly) { return; } const label = target.closest(SELECTOR_RATING_ITEM_LABEL); const labels = SelectorEngine.find(SELECTOR_RATING_ITEM_LABEL, this._element); this._resetLabels(); const input = SelectorEngine.findOne(SELECTOR_RATING_ITEM_INPUT, label.parentElement); EventHandler.trigger(this._element, EVENT_HOVER, { value: input.value }); this._createTooltip(label.parentElement, input.value); if (this._config.highlightOnlySelected) { label.classList.add(CLASS_NAME_ACTIVE); return; } for (const _label of labels) { _label.classList.add(CLASS_NAME_ACTIVE); if (_label === label) { break; } } }); EventHandler.on(this._element, EVENT_MOUSELEAVE, SELECTOR_RATING_ITEM_LABEL, () => { if (this._config.disabled || this._config.readOnly) { return; } if (this._tooltip) { this._tooltip.hide(); } const checkedInput = SelectorEngine.findOne(`${SELECTOR_RATING_ITEM_INPUT}[value="${this._currentValue}"]`, this._element); this._resetLabels(); EventHandler.trigger(this._element, EVENT_HOVER, { value: null }); if (checkedInput && this._config.highlightOnlySelected) { const label = SelectorEngine.findOne(SELECTOR_RATING_ITEM_LABEL, checkedInput.parentElement); label.classList.add(CLASS_NAME_ACTIVE); return; } if (checkedInput) { const inputs = SelectorEngine.find(SELECTOR_RATING_ITEM_INPUT, this._element); this._resetLabels(); for (const input of inputs) { const label = SelectorEngine.findOne(SELECTOR_RATING_ITEM_LABEL, input.parentElement); label.classList.add(CLASS_NAME_ACTIVE); if (input === checkedInput) { break; } } } }); EventHandler.on(this._element, EVENT_FOCUSIN, SELECTOR_RATING_ITEM_INPUT, ({ target }) => { EventHandler.trigger(this._element, EVENT_HOVER, { value: target.value }); this._createTooltip(target.parentElement, target.value); }); EventHandler.on(this._element, EVENT_FOCUSOUT, SELECTOR_RATING_ITEM_INPUT, () => { EventHandler.trigger(this._element, EVENT_HOVER, { value: null }); if (this._tooltip) { this._tooltip.hide(); } }); } _createTooltip(selector, value) { if (this._config.tooltips === false) { return; } if (this._tooltip) { this._tooltip.hide(); } let tooltipTitle; if (typeof this._config.tooltips === 'boolean') { tooltipTitle = value; } if (typeof this._config.tooltips === 'object') { tooltipTitle = this._config.tooltips[value]; } if (Array.isArray(this._config.tooltips)) { tooltipTitle = this._config.tooltips[value - 1]; } this._tooltip = new Tooltip(selector, { title: tooltipTitle }); } _configAfterMerge(config) { if (typeof config.tooltips === 'string') { config.tooltips = config.tooltips.split(','); } return config; } _resetLabels() { const labels = SelectorEngine.find(SELECTOR_RATING_ITEM_LABEL, this._element); for (const label of labels) { label.classList.remove(CLASS_NAME_ACTIVE); } } _createRating() { this._element.classList.add(CLASS_NAME_RATING); if (this._config.size) { this._element.classList.add(`rating-${this._config.size}`); } if (this._config.disabled) { this._element.classList.add(CLASS_NAME_DISABLED); } if (this._config.readOnly) { this._element.classList.add(CLASS_NAME_READONLY); } this._element.setAttribute('role', 'radiogroup'); Array.from({ length: this._config.itemCount }, (_, index) => this._createRatingItem(index)); } _createRatingItem(index) { const ratingItemElement = document.createElement('div'); ratingItemElement.classList.add(CLASS_NAME_RATING_ITEM); const numberOfRadios = 1 / this._config.precision; // eslint-disable-next-line array-callback-return Array.from({ length: numberOfRadios }, (_, _index) => { const ratingItemId = index_js.getUID(`${this.constructor.NAME}${index}`).toString(); const isNotLastItem = _index + 1 < numberOfRadios; const value = numberOfRadios === 1 ? index + 1 : (_index + 1) * Number(this._config.precision) + index; // Create label const ratingItemLabelElement = document.createElement('label'); ratingItemLabelElement.classList.add(CLASS_NAME_RATING_ITEM_LABEL); ratingItemLabelElement.setAttribute('for', ratingItemId); // eslint-disable-next-line eqeqeq if (this._config.highlightOnlySelected && this._currentValue == value) { ratingItemLabelElement.classList.add(CLASS_NAME_ACTIVE); } if (!this._config.highlightOnlySelected && this._currentValue >= value) { ratingItemLabelElement.classList.add(CLASS_NAME_ACTIVE); } if (isNotLastItem) { ratingItemLabelElement.style.zIndex = 1 / this._config.precision - _index; ratingItemLabelElement.style.position = 'absolute'; ratingItemLabelElement.style.width = `${this._config.precision * (_index + 1) * 100}%`; ratingItemLabelElement.style.overflow = 'hidden'; ratingItemLabelElement.style.opacity = 0; } if (this._config.icon) { const ratingItemIconElement = document.createElement('div'); ratingItemIconElement.classList.add(CLASS_NAME_RATING_ITEM_CUSTOM_ICON); ratingItemIconElement.innerHTML = this._sanitizeIcon(typeof this._config.icon === 'object' ? this._config.icon[index + 1] : this._config.icon); ratingItemLabelElement.append(ratingItemIconElement); } else { const ratingItemIconElement = document.createElement('div'); ratingItemIconElement.classList.add(CLASS_NAME_RATING_ITEM_ICON); ratingItemLabelElement.append(ratingItemIconElement); } if (this._config.icon && this._config.activeIcon) { const ratingItemIconActiveElement = document.createElement('div'); ratingItemIconActiveElement.classList.add(CLASS_NAME_RATING_ITEM_CUSTOM_ICON_ACTIVE); ratingItemIconActiveElement.innerHTML = this._sanitizeIcon(typeof this._config.activeIcon === 'object' ? this._config.activeIcon[index + 1] : this._config.activeIcon); ratingItemLabelElement.append(ratingItemIconActiveElement); } // Create input const ratingItemInputElement = document.createElement('input'); ratingItemInputElement.classList.add(CLASS_NAME_RATING_ITEM_INPUT); ratingItemInputElement.id = ratingItemId; ratingItemInputElement.type = 'radio'; ratingItemInputElement.value = value; ratingItemInputElement.name = this._name; if (this._config.disabled || this._config.readOnly) { ratingItemInputElement.setAttribute('disabled', true); } if (this._currentValue === value) { ratingItemInputElement.checked = true; } // Append elements if (this._config.precision === 1) { ratingItemElement.append(ratingItemLabelElement); ratingItemElement.append(ratingItemInputElement); } else { const wrapper = document.createElement('div'); wrapper.append(ratingItemLabelElement); wrapper.append(ratingItemInputElement); ratingItemElement.append(wrapper); } }); this._element.append(ratingItemElement); } _sanitizeIcon(icon) { return this._config.sanitize ? sanitizer_js.sanitizeHtml(icon, this._config.allowList, this._config.sanitizeFn) : icon; } _getConfig(config) { const dataAttributes = Manipulator.getDataAttributes(this._element); for (const dataAttribute of Object.keys(dataAttributes)) { if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) { delete dataAttributes[dataAttribute]; } } config = { ...dataAttributes, ...(typeof config === 'object' && config ? config : {}) }; config = this._mergeConfigObj(config); config = this._configAfterMerge(config); this._typeCheckConfig(config); return config; } // Static static ratingInterface(element, config) { const data = Rating.getOrCreateInstance(element, config); if (typeof config === 'string') { if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`); } data[config](); } } static jQueryInterface(config) { return this.each(function () { const data = Rating.getOrCreateInstance(this, config); if (typeof config !== 'string') { return; } if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { throw new TypeError(`No method named "${config}"`); } data[config](this); }); } } /** * Data API implementation */ EventHandler.on(window, EVENT_LOAD_DATA_API, () => { const ratings = SelectorEngine.find(SELECTOR_DATA_TOGGLE); for (let i = 0, len = ratings.length; i < len; i++) { Rating.ratingInterface(ratings[i]); } }); /** * jQuery */ index_js.defineJQueryPlugin(Rating); exports.default = Rating; exports.svgAllowList = svgAllowList; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); })); //# sourceMappingURL=rating.js.map