- // ==UserScript==
- // @name Swiggy & Zomato: Non Veg dishes only
- // @namespace http://tampermonkey.net/
- // @version 1.2.5
- // @description On Swiggy and Zomato you can select to show vegetarian dishes only, this script does the reverse: it allows you to hide vegetarian dishes. Rate individual dishes and keep a private history of what you like and what you hated
- // @author cuzi
- // @copyright 2021, cuzi (https://openuserjs.org/users/cuzi)
- // @license GPL-3.0-or-later
- // @match https://www.swiggy.com/*
- // @match https://www.zomato.com/*
- // @icon https://res.cloudinary.com/swiggy/image/upload/portal/c/icon-192x192.png
- // @grant GM.getValue
- // @grant GM.setValue
- // @grant GM_getResourceText
- // @require https://cdn.jsdelivr.net/npm/string-similarity@4.0.4/umd/string-similarity.min.js
- // @resource thumbUp https://cdn.jsdelivr.net/npm/openmoji@14.0.0/color/svg/1F44D.svg
- // @resource thumbDown https://cdn.jsdelivr.net/npm/openmoji@14.0.0/color/svg/1F44E.svg
- // @resource star https://cdn.jsdelivr.net/npm/openmoji@14.0.0/color/svg/2B50.svg
- // ==/UserScript==
-
- /*
- Copyright (C) 2021, cuzi (https://openuserjs.org/users/cuzi)
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
- /* globals Node, GM, GM_getResourceText, stringSimilarity */
-
- (function () {
- 'use strict'
-
- const DEFAULT_DATA = '{"restaurants": {}}'
-
- function timeSince (date) {
- // https://stackoverflow.com/a/72973090/
- const MINUTE = 60
- const HOUR = MINUTE * 60
- const DAY = HOUR * 24
- const WEEK = DAY * 7
- const MONTH = DAY * 30
- const YEAR = DAY * 365
- const secondsAgo = Math.round((Date.now() - Number(date)) / 1000)
- if (secondsAgo < MINUTE) {
- return secondsAgo + ` second${secondsAgo !== 1 ? 's' : ''} ago`
- }
- let divisor
- let unit = ''
- if (secondsAgo < HOUR) {
- [divisor, unit] = [MINUTE, 'minute']
- } else if (secondsAgo < DAY) {
- [divisor, unit] = [HOUR, 'hour']
- } else if (secondsAgo < WEEK) {
- [divisor, unit] = [DAY, 'day']
- } else if (secondsAgo < MONTH) {
- [divisor, unit] = [WEEK, 'week']
- } else if (secondsAgo < YEAR) {
- [divisor, unit] = [MONTH, 'month']
- } else {
- [divisor, unit] = [YEAR, 'year']
- }
- const count = Math.floor(secondsAgo / divisor)
- return `${count} ${unit}${count > 1 ? 's' : ''} ago`
- }
-
- function symmetricDifference (setA, setB) {
- const _difference = new Set(setA)
- for (const elem of setB) {
- if (_difference.has(elem)) {
- _difference.delete(elem)
- } else {
- _difference.add(elem)
- }
- }
- return _difference
- }
-
- function compareNames (s0, s1) {
- let r = 0
- s0 = s0.toLowerCase().trim()
- s1 = s1.toLowerCase().trim()
- if (s0 === s1) {
- return 2
- }
- const set0 = new Set(s0.split(/\s+/))
- const set1 = new Set(s1.split(/\s+/))
- r -= symmetricDifference(set0, set1).size
- if (r < 0) {
- r += stringSimilarity.compareTwoStrings(s0, s1)
- }
- return r
- }
-
- function getThumbs (onUpClick, onDownClick) {
- const thumbs = document.createElement('div')
- thumbs.classList.add('thumbscontainer')
- const thumbUpSVG = document.createElement('div')
- thumbUpSVG.style.width = '40px'
- thumbUpSVG.style.height = '40px'
- thumbUpSVG.style.float = 'left'
- thumbUpSVG.style.cursor = 'pointer'
- thumbUpSVG.innerHTML = GM_getResourceText('thumbUp').replace('id="emoji"', 'id="thumbUp' + Math.random() + '"')
- thumbUpSVG.querySelector('#skin polygon').setAttribute('fill', '#cccccc')
- thumbUpSVG.addEventListener('click', onUpClick)
- thumbs.appendChild(thumbUpSVG)
- const thumbDownSVG = document.createElement('div')
- thumbDownSVG.style.width = '40px'
- thumbDownSVG.style.height = '40px'
- thumbDownSVG.style.float = 'left'
- thumbDownSVG.style.cursor = 'pointer'
- thumbDownSVG.innerHTML = GM_getResourceText('thumbDown').replace('id="emoji"', 'id="thumbDown' + Math.random() + '"')
- thumbDownSVG.querySelector('#skin polygon').setAttribute('fill', '#cccccc')
- thumbDownSVG.addEventListener('click', onDownClick)
- thumbs.appendChild(thumbDownSVG)
- thumbs.appendChild(document.createElement('div')).style.clear = 'left'
- return [thumbs, thumbUpSVG, thumbDownSVG]
- }
-
- function clearAllRatings () {
- const promises = []
- for (const gmKey of ['swiggy', 'zomato']) {
- promises.push(GM.setValue(gmKey, DEFAULT_DATA))
- }
- Promise.all(promises).then(() => {
- window.alert('All ratings cleared\n\nReload the page to see the changes')
- document.location.reload()
- })
- }
- async function clearRestaurantRatings (node) {
- const gmKey = node.dataset.gmKey
- const restaurantId = node.dataset.restaurantId
- const restaurantName = node.dataset.restaurantName
-
- if (!gmKey || !restaurantId) {
- return false
- }
-
- if (!window.confirm('Clear all ratings for this restaurant?\n\n' + restaurantName + '\n\nThis cannot be undone!')) {
- return false
- }
-
- const data = JSON.parse(await GM.getValue(gmKey, DEFAULT_DATA))
- if ((restaurantId in data.restaurants)) {
- delete data.restaurants[restaurantId]
- }
- await GM.setValue(gmKey, JSON.stringify(data))
- return true
- }
-
- async function listRatings (mGmKey, selectedRestaurantId) {
- const showRestaurantDishes = function (data, listDiv, restaurantId, gmKey) {
- const info = data.restaurants[restaurantId].info
- const dishes = data.restaurants[restaurantId].dishes
- if (!dishes) {
- return
- }
- const restaDiv = listDiv.appendChild(document.createElement('div'))
- restaDiv.classList.add('restaurant_container')
- const metaDiv = restaDiv.appendChild(document.createElement('div'))
- metaDiv.classList.add('ratings_meta')
- const ra = metaDiv.appendChild(document.createElement('a'))
- ra.href = info.url
- const label = 'name' in info ? info.name : info.url
- ra.appendChild(document.createTextNode(label))
- if ('location' in info && info.location && info.location.trim()) {
- const span = metaDiv.appendChild(document.createElement('span'))
- span.appendChild(document.createTextNode(` (${info.location})`))
- }
- const lastOverallRatingSpan = metaDiv.appendChild(document.createElement('span'))
- const clearButton = metaDiv.appendChild(document.createElement('button'))
- clearButton.style.fontSize = 'small'
- clearButton.style.marginLeft = '3px'
- clearButton.addEventListener('click', function () {
- clearRestaurantRatings(this).then(function (cleared) {
- if (cleared) {
- document.location.reload()
- }
- })
- })
- clearButton.dataset.restaurantId = restaurantId
- clearButton.dataset.gmKey = gmKey
- clearButton.dataset.restaurantName = label
- clearButton.appendChild(document.createTextNode('Clear'))
- const listDivUp = restaDiv.appendChild(document.createElement('div'))
- const listDivDown = restaDiv.appendChild(document.createElement('div'))
- listDivUp.classList.add('ratings_list', 'up')
- listDivDown.classList.add('ratings_list', 'down')
- restaDiv.appendChild(document.createElement('div')).style.clear = 'left'
- let lastRating = null
- for (const dishName in dishes) {
- const dish = dishes[dishName]
- const div = dish.rating > 0 ? listDivUp : listDivDown
- const le = div.appendChild(document.createElement('div'))
- le.classList.add('ratings_item')
- le.appendChild(document.createTextNode(dishName))
- if ('price' in dish && dish.price) {
- le.appendChild(document.createTextNode(` ₹${dish.price}`))
- }
- if ('veg' in dish && dish.veg) {
- const span = le.appendChild(document.createElement('span'))
- if (dish.veg === 'veg') {
- span.classList.add('veggy_icon')
- span.appendChild(document.createTextNode('\u23FA'))
- } else {
- span.classList.add('nonveggy_icon')
- span.appendChild(document.createTextNode('\u2BC5'))
- }
- }
- const date = new Date(dish.lastRating)
- const dateStr = 'Rated: ' + date.toLocaleDateString() + ' ' + timeSince(date)
- le.setAttribute('title', dateStr)
- if (lastRating == null || date > lastRating) {
- lastRating = date
- }
- }
- if (lastRating) {
- const dateStr = ' ' + lastRating.toLocaleDateString() + ' ' + timeSince(lastRating)
- lastOverallRatingSpan.appendChild(document.createTextNode(dateStr))
- }
- }
-
- let listDiv = document.getElementById('ratings_container')
- if (!listDiv) {
- createMainContainer(mGmKey, selectedRestaurantId)
- listDiv = document.getElementById('ratings_container')
- }
- listDiv.innerHTML = ''
-
- for (const gmKey of ['swiggy', 'zomato']) {
- const data = JSON.parse(await GM.getValue(gmKey, DEFAULT_DATA))
- if (selectedRestaurantId && selectedRestaurantId in data.restaurants) {
- // Show current restaurant first
- showRestaurantDishes(data, listDiv, selectedRestaurantId, gmKey)
- }
- for (const restaurantId in data.restaurants) {
- if (!selectedRestaurantId || selectedRestaurantId !== restaurantId) {
- showRestaurantDishes(data, listDiv, restaurantId, gmKey)
- }
- }
- }
- }
-
- function crossCheckNames (name, data) {
- const results = []
- for (const restaurantId in data.restaurants) {
- if (!('name' in data.restaurants[restaurantId].info)) {
- continue
- }
- const r = compareNames(data.restaurants[restaurantId].info.name, name)
- if (r > -2) {
- results.push([r, data.restaurants[restaurantId]])
- }
- }
- return results.sort((a, b) => b[0] - a[0]).map(v => v[1])
- }
-
- async function crossCheck (restaurantId, restaurantInfo, gmKey) {
- if (!('name' in restaurantInfo) || !restaurantInfo.name) {
- return
- }
-
- const data = JSON.parse(await GM.getValue(gmKey === 'swiggy' ? 'zomato' : 'swiggy', DEFAULT_DATA))
-
- const results = crossCheckNames(restaurantInfo.name, data)
- showCrossCheckResults(gmKey, restaurantId, results)
- }
-
- function showCrossCheckResultsWide () {
- document.getElementById('cross_check_results').classList.add('fullscreen')
- try {
- this.remove()
- } catch (e) {}
-
- document.head.appendChild(document.createElement('style')).innerHTML = `
- #cross_check_results.fullscreen {
- top: 5px;
- right:5px;
- height: 95%;
- width: 95%;
- max-width: 95%;
- max-height: 95%;
- }
-
- #cross_check_results.fullscreen .ratings_list {
- width:45%;
- float:left;
- }
- `
- }
-
- function showCrossCheckResults (gmKey, restaurantId, results) {
- if (!results.length) {
- return
- }
- const div = createMainContainer(gmKey, restaurantId)
-
- const resultsHead = div.appendChild(document.createElement('div'))
- resultsHead.appendChild(document.createTextNode('Similar named restaurants you voted on ' + (gmKey === 'swiggy' ? 'Zomato' : 'Swiggy')))
- resultsHead.style.fontWeight = 'bold'
-
- const resultsDiv = div.appendChild(document.createElement('div'))
- results.forEach(function (restaurant, i) {
- const restaurantDiv = resultsDiv.appendChild(document.createElement('div'))
- if (i % 2 === 0) {
- restaurantDiv.style.backgroundColor = '#ddd'
- }
- const restaurantName = restaurantDiv.appendChild(document.createElement('div'))
- restaurantName.appendChild(document.createTextNode(restaurant.info.name))
- const restaurantLoc = restaurantDiv.appendChild(document.createElement('div'))
- restaurantLoc.appendChild(document.createTextNode(restaurant.info.location || ''))
- restaurantLoc.style.fontSize = '10pt'
- const restaurantLink = restaurantDiv.appendChild(document.createElement('a'))
- restaurantLink.appendChild(document.createTextNode(restaurant.info.url))
- restaurantLink.setAttribute('href', restaurant.info.url)
- restaurantLink.style.fontSize = '7pt'
- })
- }
-
- function createMainContainer (gmKey = 'swiggy', restaurantId = null, clear = false) {
- let div = document.getElementById('cross_check_results')
- if (!div) {
- div = document.body.appendChild(document.createElement('div'))
- div.setAttribute('id', 'cross_check_results')
- document.head.appendChild(document.createElement('style')).innerHTML = `
- #cross_check_results {
- z-index:1200;
- position:fixed;
- top: 100px;
- right:5px;
- max-height: 70%;
- max-width: 20%;
- overflow: auto;
- border:2px solid #223075;
- background:white;
- font-size:12pt
- }
- #cross_check_results button {
- border: 1px solid #777;
- border-radius: 4px;
- background: #e0e0e0;
- }
- #cross_check_results button:hover {
- border: 1px solid #000;
- border-radius: 4px;
- background: #f0f0f0;
- }
-
- #cross_check_results a:link {
- text-decoration:underline;
- color:#06c;
- }
- #cross_check_results a:visited {
- text-decoration:underline;
- color:#06c;
- }
-
- #cross_check_results .restaurant_container {
- border-bottom: 2px solid #848484;
- }
-
- #cross_check_results .ratings_meta {
- background-color:#f4e9bc;
- background-image: linear-gradient(to right, white , #f4e9bc);
- margin-top:3px;
- }
-
- #cross_check_results .ratings_list {
- float:left;
- margin: 2px;
- }
- #cross_check_results .ratings_list.up {
- background-color:#e6ffe6;
- }
- #cross_check_results .ratings_list.down {
- background-color:#fbd5d5;
- margin-left: 5px;
- }
- #cross_check_results .ratings_item:nth-child(2n+2){
- background-color:#0000000f;
- }
- #cross_check_results .veggy_icon {
- color: #0f8a65;
- border: 2px solid #0f8a65;
- font-size: 8px;
- height: 13px;
- display: inline-block;
- font-weight: 1000;
- width: 12px;
- vertical-align: middle;
- margin: 1px;
- }
- #cross_check_results .nonveggy_icon {
- color: #e43b4f;
- border: 2px solid #e43b4f;
- font-size: 8px;
- height: 13px;
- display: inline-block;
- font-weight: 1000;
- width: 12px;
- vertical-align: middle;
- margin: 1px;
- }
-
- #cross_check_results .ratings_meta span {
- color: #555;
- font-size: 10pt;
- }
-
- `
-
- const controlsDiv = div.appendChild(document.createElement('div'))
- controlsDiv.setAttribute('id', 'controls_container')
-
- const closeButton = controlsDiv.appendChild(document.createElement('button'))
- closeButton.appendChild(document.createTextNode('Close'))
- closeButton.addEventListener('click', function () {
- removeMainContainer()
- showCrossCheckResults(gmKey, restaurantId, [])
- })
-
- const clearButton = controlsDiv.appendChild(document.createElement('button'))
- clearButton.appendChild(document.createTextNode('Clear all'))
- clearButton.addEventListener('click', function () {
- if (window.confirm('Delete ratings for all restaurants?') && window.confirm('Delete ratings for ALL restaurants?\n\nAre you sure?')) {
- clearAllRatings()
- }
- })
-
- const fullscreenButton = controlsDiv.appendChild(document.createElement('button'))
- fullscreenButton.appendChild(document.createTextNode('\u27F7'))
- fullscreenButton.addEventListener('click', showCrossCheckResultsWide)
-
- const listDiv = div.appendChild(document.createElement('div'))
- listDiv.setAttribute('id', 'ratings_container')
- const listButton = listDiv.appendChild(document.createElement('button'))
- listButton.appendChild(document.createTextNode('View ratings'))
- listButton.addEventListener('click', () => listRatings(gmKey, restaurantId))
- }
-
- if (clear) {
- div.classList.remove('fullscreen')
- div.innerHTML = ''
- }
-
- div.style.display = 'block'
-
- return div
- }
-
- function removeMainContainer () {
- const div = document.getElementById('cross_check_results')
- if (div) {
- div.remove()
- }
- }
-
- if (document.location.hostname.endsWith('.swiggy.com')) {
- let crossCheckDone = false
- const getRestaurantInfo = function () {
- const results = {}
- const h1 = document.querySelector('[class*="RestaurantNameAddress_name"]')
- if (h1) {
- results.name = h1.textContent.trim()
- }
- try {
- results.location = document.querySelector('[class*="RestaurantNameAddress_area"]').textContent.trim()
- } catch (e) {
- console.log(e)
- }
- return results
- }
- const addRatingsButton = function () {
- if (document.getElementById('nav_rating_button')) {
- return
- }
- if (document.querySelector('.global-nav a[href*="/support"]')) {
- const orgLi = document.querySelector('.global-nav a[href*="/support"]').parentNode.parentNode
- const li = orgLi.cloneNode(true)
- orgLi.parentNode.appendChild(li)
- li.setAttribute('id', 'nav_rating_button')
- li.addEventListener('click', function (ev) {
- ev.preventDefault()
- listRatings('swiggy', null)
- })
- li.querySelector('a').href = '#'
- const svg = li.querySelector('svg')
- const span = svg.parentNode
- span.parentNode.replaceChild(document.createTextNode('Ratings'), span.nextSibling)
- const starSVG = document.createElement('div')
- starSVG.style.width = '22px'
- starSVG.style.height = '22px'
- starSVG.style.cursor = 'pointer'
- starSVG.innerHTML = GM_getResourceText('star').replace('id="emoji"', 'id="starSVG' + Math.random() + '"')
- starSVG.querySelector('#color polygon').setAttribute('fill', '#ffffff')
- starSVG.querySelector('#line polygon').setAttribute('stroke', '#3d4152')
- starSVG.querySelector('#line polygon').setAttribute('stroke-width', '6')
- span.replaceChild(starSVG, svg)
- } else if (!document.getElementById('cross_check_results')) {
- createMainContainer('swiggy', null)
- }
- }
- const addRatings = async function () {
- const m = document.location.pathname.match(/\/restaurants\/[\w-]+-(\d+)/)
- if (!m) {
- return
- }
- const restaurantId = m[1]
-
- let data = JSON.parse(await GM.getValue('swiggy', DEFAULT_DATA))
- if (!(restaurantId in data.restaurants)) {
- data.restaurants[restaurantId] = { dishes: {}, info: { id: restaurantId, url: document.location.href } }
- }
-
- if (!crossCheckDone) {
- crossCheckDone = true
- crossCheck(restaurantId, getRestaurantInfo(), 'swiggy')
- }
-
- document.querySelectorAll('[data-testid*="dish-item"]').forEach(function (menuItem) {
- if ('userscriptprocessed' in menuItem.dataset) {
- return
- }
- menuItem.dataset.userscriptprocessed = 1
- const dishName = menuItem.querySelector('[class*=itemNameText]').textContent.trim()
- const saveRating = async function (rating) {
- let price = null
- try {
- price = parseInt(menuItem.querySelector('.rupee').textContent.trim())
- } catch (e) {
- console.log(e)
- }
- let veg = null
- const icon = menuItem.querySelector('[class*=styles_icon]')
- if (icon && icon.className.match(/icon-?([a-z]+)/i)) {
- veg = icon.className.match(/icon-?([a-z]+)/i)[1].toLowerCase() // "veg", "nonveg"
- }
- data = JSON.parse(await GM.getValue('swiggy', DEFAULT_DATA))
- if (!(restaurantId in data.restaurants)) {
- data.restaurants[restaurantId] = { dishes: {}, info: { id: restaurantId, url: document.location.href } }
- }
- if (!(dishName in data.restaurants[restaurantId].dishes)) {
- data.restaurants[restaurantId].dishes[dishName] = {
- name: dishName,
- price,
- veg,
- lastRating: new Date().toJSON().toString()
- }
- }
- data.restaurants[restaurantId].dishes[dishName].rating = rating
- data.restaurants[restaurantId].info = Object.assign(data.restaurants[restaurantId].info, getRestaurantInfo())
- await GM.setValue('swiggy', JSON.stringify(data))
- }
-
- const onUp = function () {
- saveRating(1).then(function () {
- thumbUp.querySelector('#skin polygon').setAttribute('fill', '#50c020')
- thumbDown.querySelector('#skin polygon').setAttribute('fill', '#cccccc')
- })
- }
- const onDown = function () {
- saveRating(-1).then(function () {
- thumbUp.querySelector('#skin polygon').setAttribute('fill', '#cccccc')
- thumbDown.querySelector('#skin polygon').setAttribute('fill', '#e60000')
- })
- }
-
- const [thumbs, thumbUp, thumbDown] = getThumbs(onUp, onDown)
- const parentContainer = menuItem.querySelector('[class*=itemImageContainer]')
- thumbs.style.position = 'relative'
- thumbs.style.zIndex = 1
- if (parentContainer.className.indexOf('NoImage') === -1) {
- thumbs.style.marginTop = '20pt'
- }
- parentContainer.appendChild(thumbs)
- if (dishName in data.restaurants[restaurantId].dishes) {
- if (data.restaurants[restaurantId].dishes[dishName].rating > 0) {
- thumbUp.querySelector('#skin polygon').setAttribute('fill', '#50c020')
- } else if (data.restaurants[restaurantId].dishes[dishName].rating < 0) {
- thumbDown.querySelector('#skin polygon').setAttribute('fill', '#e60000')
- }
- const dateDiv = thumbs.appendChild(document.createElement('div'))
- const date = new Date(data.restaurants[restaurantId].dishes[dishName].lastRating)
- const dateStr = date.toLocaleDateString() + ' ' + timeSince(date)
- dateDiv.style.fontSize = '10px'
- dateDiv.appendChild(document.createTextNode(dateStr))
- }
- })
- }
- const addNonVegToggle = function () {
- let orgDiv
- let newDiv
- let isActive
- const orgClick = function () {
- if (isActive) {
- console.debug('orgClick: already non-veg, reset it')
- resetNonVeg()
- }
- }
- const resetNonVeg = function () {
- document.querySelectorAll('.hiddenbyscript').forEach(function (menuItem) {
- menuItem.classList.remove('hiddenbyscript')
- menuItem.style.display = ''
- })
- isActive = false
- newDiv.querySelector('[class*="ToggleSwitch_toggleBar"]').style.backgroundColor = ''
- newDiv.querySelector('[class*="ToggleSwitch_toggleThumb"]').style.backgroundColor = ''
- newDiv.querySelector('[class*="ToggleSwitch_toggleThumb"]').style.transform = ''
- }
- const enableNonVeg = function (ev) {
- if (ev) {
- ev.preventDefault()
- ev.stopPropagation()
- }
- if (isActive) {
- console.debug('enableNonVeg: already non-veg, reset it')
- window.setTimeout(resetNonVeg, 100)
- return
- }
-
- if (orgDiv.querySelector('[class*="toggleThumbActive"]')) {
- console.debug('enableNonVeg: org checkbox is checked, click it and wait')
- orgDiv.querySelector('button').click()
- window.setTimeout(enableNonVeg, 500)
- newDiv.querySelector('[class*="ToggleSwitch_toggleBar"]').style.backgroundColor = '#87d'
- return
- }
-
- console.debug('enableNonVeg: hide menu items')
- document.querySelectorAll('[data-testid*="dish-item"]').forEach(function (menuItem) {
- const icon = menuItem.querySelector('[class*=styles_icon]')
- if (icon && icon.className.match(/icon-?veg/i)) {
- menuItem.classList.add('hiddenbyscript')
- menuItem.style.display = 'none'
- }
- })
- isActive = true
- newDiv.querySelector('[class*="ToggleSwitch_toggleBar"]').style.backgroundColor = '#e43b4f'
- newDiv.querySelector('[class*="ToggleSwitch_toggleThumb"]').style.backgroundColor = '#e43b4f'
- newDiv.querySelector('[class*="ToggleSwitch_toggleThumb"]').style.transform = 'translate3d(18px,0,0)'
- }
- const labels = document.querySelectorAll('[data-testid*="filter-switch"]')
- labels.forEach(function (label) {
- if (label.className.indexOf('vegOnly') !== -1) {
- orgDiv = label
- orgDiv.parentNode.style.justifyContent = 'flex-start'
- newDiv = orgDiv.parentNode.appendChild(label.cloneNode(true))
- newDiv.style.marginLeft = '1em'
- newDiv.setAttribute('id', 'nonVegToggle')
- newDiv.querySelector('[class*="Label_"]').textContent = 'Non veg'
- newDiv.querySelector('button').addEventListener('click', enableNonVeg)
- orgDiv.querySelector('button').addEventListener('click', orgClick)
- }
- })
- }
- window.setInterval(function () {
- addRatingsButton()
- addRatings()
- if (!document.getElementById('nonVegToggle')) {
- addNonVegToggle()
- }
- }, 1000)
- } else if (document.location.hostname.endsWith('.zomato.com')) {
- let crossCheckDone = false
- const getRestaurantInfo = function () {
- const results = {}
- const h1 = document.querySelector('div#root main section>div>div>div>h1')
- if (h1) {
- results.name = h1.textContent.trim()
- }
- try {
- results.location = h1.parentNode.nextElementSibling.firstChild.nextElementSibling.textContent.trim()
- } catch (e) {
- console.log(e)
- }
- return results
- }
- const addRatingsButton = function () {
- if (document.getElementById('nav_rating_button')) {
- return
- }
- if (document.querySelector('ul[id*=navigation]')) {
- const orgLi = document.querySelector('ul[id*=navigation]').querySelector('li:last-child')
- const li = orgLi.cloneNode(true)
- orgLi.parentNode.appendChild(li)
- li.setAttribute('id', 'nav_rating_button')
- li.addEventListener('click', function (ev) {
- ev.preventDefault()
- listRatings('zomato', null)
- })
- const a = li.querySelector('a')
- a.innerHTML = ''
- a.style.fontSize = '10px'
- const starSVG = document.createElement('div')
- starSVG.style.width = '22px'
- starSVG.style.height = '22px'
- starSVG.style.cursor = 'pointer'
- starSVG.style.margin = 'auto'
- starSVG.style.marginTop = '-35px'
- starSVG.innerHTML = GM_getResourceText('star').replace('id="emoji"', 'id="starSVG' + Math.random() + '"')
- starSVG.querySelector('#color polygon').setAttribute('fill', '#EF4F5F')
- a.appendChild(starSVG)
- a.appendChild(document.createTextNode('Ratings'))
- } else if (!document.getElementById('cross_check_results')) {
- createMainContainer('zomato', null)
- }
- }
- const addRatings = async function () {
- const m = document.location.pathname.match(/([\w-]+\/[\w-]+)\/order/)
- if (!m) {
- return
- }
- const restaurantId = m[1]
-
- let data = JSON.parse(await GM.getValue('zomato', DEFAULT_DATA))
- if (!(restaurantId in data.restaurants)) {
- data.restaurants[restaurantId] = { dishes: {}, info: { id: restaurantId, url: document.location.href } }
- }
-
- if (!crossCheckDone) {
- crossCheckDone = true
- crossCheck(restaurantId, getRestaurantInfo(), 'zomato')
- }
-
- document.querySelectorAll('[type="veg"],[type="non-veg"]').forEach(function (symbol) {
- const menuItem = symbol.parentNode.parentNode.parentNode
- if ('userscriptprocessed' in menuItem.dataset) {
- return
- }
- menuItem.dataset.userscriptprocessed = 1
- const dishName = menuItem.querySelector('h4').textContent.trim()
- const saveRating = async function (rating) {
- let price = null
- try {
- price = parseInt(menuItem.textContent.match(/₹\s*(\d+)/)[1])
- } catch (e) {
- console.log(e)
- }
- const veg = symbol.getAttribute('type').toLowerCase().replace('-', '') // "veg", "nonveg"
- data = JSON.parse(await GM.getValue('zomato', DEFAULT_DATA))
- if (!(restaurantId in data.restaurants)) {
- data.restaurants[restaurantId] = { dishes: {}, info: { id: restaurantId, url: document.location.href } }
- }
- if (!(dishName in data.restaurants[restaurantId].dishes)) {
- data.restaurants[restaurantId].dishes[dishName] = {
- name: dishName,
- price,
- veg, // "veg", "nonveg"
- lastRating: new Date().toJSON().toString()
- }
- }
- data.restaurants[restaurantId].dishes[dishName].rating = rating
- data.restaurants[restaurantId].info = Object.assign(data.restaurants[restaurantId].info, getRestaurantInfo())
- await GM.setValue('zomato', JSON.stringify(data))
- }
-
- const onUp = function () {
- saveRating(1).then(function () {
- thumbUp.querySelector('#skin polygon').setAttribute('fill', '#50c020')
- thumbDown.querySelector('#skin polygon').setAttribute('fill', '#cccccc')
- })
- }
- const onDown = function () {
- saveRating(-1).then(function () {
- thumbUp.querySelector('#skin polygon').setAttribute('fill', '#cccccc')
- thumbDown.querySelector('#skin polygon').setAttribute('fill', '#e60000')
- })
- }
-
- const [thumbs, thumbUp, thumbDown] = getThumbs(onUp, onDown)
- thumbs.style.marginTop = '20pt'
- menuItem.firstChild.appendChild(thumbs)
- if (dishName in data.restaurants[restaurantId].dishes) {
- if (data.restaurants[restaurantId].dishes[dishName].rating > 0) {
- thumbUp.querySelector('#skin polygon').setAttribute('fill', '#50c020')
- } else if (data.restaurants[restaurantId].dishes[dishName].rating < 0) {
- thumbDown.querySelector('#skin polygon').setAttribute('fill', '#e60000')
- }
- const dateDiv = thumbs.appendChild(document.createElement('div'))
- const date = new Date(data.restaurants[restaurantId].dishes[dishName].lastRating)
- const dateStr = date.toLocaleDateString() + ' ' + timeSince(date)
- dateDiv.style.fontSize = '10px'
- dateDiv.appendChild(document.createTextNode(dateStr))
- }
- })
- }
- const addNonVegToggle = function () {
- let label
- let orgDiv
- let newDiv
- let newCheckbox
- const orgClick = function () {
- if (newCheckbox.checked) {
- console.debug('orgClick: already non-veg, reset it')
- resetNonVeg()
- }
- }
- const resetNonVeg = function () {
- document.querySelectorAll('.hiddenbyscript').forEach(function (menuItem) {
- menuItem.classList.remove('hiddenbyscript')
- menuItem.style.display = ''
- })
- newCheckbox.checked = false
- newCheckbox.style.backgroundColor = ''
- }
- const enableNonVeg = function (ev) {
- if (ev) {
- ev.preventDefault()
- ev.stopPropagation()
- }
- newCheckbox.style.backgroundColor = '#87d'
- window.setTimeout(function () {
- if (newCheckbox.checked) {
- console.debug('enableNonVeg: already non-veg, reset it')
- window.setTimeout(resetNonVeg, 200)
- return
- }
-
- if (orgDiv.checked) {
- console.debug('enableNonVeg: org checkbox is checked, click it and wait')
- orgDiv.click()
- window.setTimeout(enableNonVeg, 500)
- return
- }
-
- console.debug('enableNonVeg: hide menu items')
- document.querySelectorAll('[type="veg"]').forEach(function (symbol) {
- const menuItem = symbol.parentNode.parentNode.parentNode
- menuItem.classList.add('hiddenbyscript')
- menuItem.style.display = 'none'
- })
- newCheckbox.checked = true
- newCheckbox.style.backgroundColor = ''
- }, 100)
- }
- const labels = document.querySelectorAll('label')
- labels.forEach(function (l) {
- if (l.textContent.toLowerCase().indexOf('veg') !== -1 && l.textContent.toLowerCase().indexOf('only') !== -1) {
- label = l
- orgDiv = label
- newDiv = orgDiv.cloneNode(true)
- label.parentNode.appendChild(newDiv)
- label.parentNode.style.width = (label.parentNode.clientWidth + newDiv.clientWidth + 17) + 'px'
- newCheckbox = newDiv.querySelector('input[type=checkbox]')
- newCheckbox.checked = false
- newDiv.setAttribute('id', 'nonVegToggle')
- newDiv.childNodes.forEach(function (c) {
- if (c.nodeType === Node.TEXT_NODE && c.textContent.toLowerCase().indexOf('veg') !== -1) {
- c.textContent = 'Non veg'
- }
- })
- newDiv.addEventListener('click', enableNonVeg)
- orgDiv.addEventListener('click', orgClick)
- }
- })
- }
- window.setInterval(function () {
- addRatingsButton()
- addRatings()
- if (!document.getElementById('nonVegToggle')) {
- addNonVegToggle()
- }
- }, 1000)
- }
- })()