UNPKG

starry-rating

Version:

JavaScript star rating system

260 lines (212 loc) 8.91 kB
/** * author: Andre Sieverding https://github.com/Teddy95 * license: MIT http://opensource.org/licenses/MIT * * The MIT License (MIT) * * Copyright (c) 2020 Andre Sieverding * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // Import default icons import icon from './icons.json' // Star rating class class Starry { // Constructor method -> saves configs to Starry object & calls build method constructor (domElement = false, config = {}) { if (!domElement) { console.error(`Starry: Missing DOM element!`) return false } if (!this.setConfig(config)) { return false } this.domElement = domElement this.build() } // Save configs to Starry object setConfig (config) { this.config = config if (typeof this.config.stars === 'undefined') this.config.stars = 5 if (typeof this.config.multiRating === 'undefined') this.config.multiRating = true if (typeof this.config.beginWith === 'undefined') this.config.beginWith = 0 if (typeof this.config.readOnly === 'undefined') this.config.readOnly = false if (typeof this.config.staticActiveRating === 'undefined') this.config.staticActiveRating = true if (typeof this.config.setStarsAfterRating === 'undefined') this.config.setStarsAfterRating = true if (typeof this.config.labels === 'undefined' || !Array.isArray(this.config.labels)) this.config.labels = false if (typeof this.config.onRate === 'undefined') this.config.onRate = (value) => true if (typeof this.currentRating === 'undefined') this.currentRating = 0 if (typeof this.config.icons === 'undefined' || typeof this.config.icons.blank === 'undefined' || typeof this.config.icons.hover === 'undefined' || typeof this.config.icons.active === 'undefined') { this.config.icons = icon } if (this.config.beginWith < 0) this.config.beginWith = 0 if (this.config.beginWith > 100) this.config.beginWith = 100 if (typeof this.config.name === 'undefined') { if (this.config.multiRating === false) { console.error(`Starry: Give your Starry star rating elements with multi rating a name!`) return false } else { this.config.name = 'Starry_' + Date.now() } } return true } // Set read only option by cookie checkCookie () { var cookies = document.cookie cookies = cookies.split(';') for (var cookie of cookies) { if (cookie.trim() === 'Starry_' + this.config.name + '=true') { this.config.readOnly = true } } } // Set rated cookie setCookie () { var time = new Date() time.setTime(time.getTime() + (1000*60*60*24*30*12*10)) document.cookie = "Starry_" + this.config.name + "=true; expires=" + time.toGMTString() + "; sameSite=Lax" this.config.multiRating = false this.config.readOnly = true } // Create star rating html build () { this.clear() if (this.config.multiRating === false) { this.checkCookie() } // Build starry wrapper var starryWrapper = document.createElement('div') starryWrapper.classList.add('Starry') starryWrapper.setAttribute('data-name', this.config.name) // Build starry inners -> blank stars var starryInnerBlank = document.createElement('div') starryInnerBlank.classList.add('Starry-blank') // Add stars to starry inners -> blank stars for (var starEl of this.getStarRow('blank')) { starryInnerBlank.appendChild(starEl) } // Build starry inners -> active stars var starryInnerActive = document.createElement('div') starryInnerActive.classList.add('Starry-active') if (this.config.staticActiveRating === true || this.config.readOnly === true) starryInnerActive.classList.add('Starry-static') starryInnerActive.style.width = `${this.config.beginWith}%` // Add stars to starry inners -> active stars for (var starEl of this.getStarRow('active')) { starryInnerActive.appendChild(starEl) } if (this.config.readOnly === false) { // Build starry inners -> hover stars var starryInnerHover = document.createElement('div') starryInnerHover.classList.add('Starry-hover') // Add stars to starry inners -> hover stars for (var starEl of this.getStarRow('hover')) { starryInnerHover.appendChild(starEl) } } // Append starry inners to starry wrapper starryWrapper.appendChild(starryInnerBlank) starryWrapper.appendChild(starryInnerActive) if (this.config.readOnly === false) starryWrapper.appendChild(starryInnerHover) // Append Starry element to star rating dom element this.domElement.appendChild(starryWrapper) // Perform on render method if it exists if (typeof this.config.onRender !== 'undefined' && typeof this.config.onRender === 'function') this.config.onRender() } // Get stars html getStarRow (type) { var stars = [] for (var i = this.config.stars; i > 0; i--) { // Build star element var starElement = document.createElement('div') starElement.classList.add('Starry-star') // Add event listener for hovering stars if (type === 'hover') { starElement.setAttribute('data-value', i) if (Array.isArray(this.config.labels)) { starElement.setAttribute('title', this.config.labels[i - 1]) starElement.setAttribute('data-label', this.config.labels[i - 1]) starElement.setAttribute('data-tooltip', this.config.labels[i - 1]) } starElement.addEventListener('click', (event) => { var targetEl = event.target if (!targetEl.classList.contains('Starry-star')) { targetEl = event.target.closest('.Starry-star') } const onRateResult = this.config.onRate(targetEl.getAttribute('data-value')) if (onRateResult !== false) { this.currentRating = parseInt(targetEl.getAttribute('data-value')) if (this.config.setStarsAfterRating === true) { this.config.beginWith = (this.currentRating / this.config.stars) * 100 } } if (this.config.multiRating === false) { this.setCookie() } this.build() }) } // Build star visual var starVisual = document.createElement('img') starVisual.setAttribute('src', this.config.icons[type]) starElement.appendChild(starVisual) // Push star element to stars array stars.push(starElement) } return stars } // Clear Starry html DOM clear () { if (typeof this.config.onClear !== 'undefined' && typeof this.config.onClear === 'function') this.config.onClear() this.domElement.innerHTML = '' } // Update starry update (config) { this.setConfig(Object.assign({}, this.config, config)) this.build() } // Get current rating getCurrentRating () { return this.currentRating } // Get config object getConfig () { return this.config } // Custom event listener on (eventName, callbackFunction) { switch (eventName) { case 'rate': this.config.onRate = callbackFunction break case 'render': this.config.onRender = callbackFunction break case 'clear': this.config.onClear = callbackFunction break default: console.error(`Starry: Event '${eventName}' doesn't exists!`) return } } }