Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 119 additions & 25 deletions WME-URComments-Enhanced.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// ==UserScript==
// @name WME URComments-Enhanced
// @namespace https://greasyfork.org/users/166843
// @version 2025.12.09.01
// @version 2026.04.01.01
// eslint-disable-next-line max-len
// @description URComments-Enhanced (URC-E) allows Waze editors to handle WME update requests more quickly and efficiently. Also adds many UR filtering options, ability to change the markers, plus much, much, more!
// @grant GM_xmlhttpRequest
// @match *://*.waze.com/*editor*
// @exclude *://*.waze.com/user/editor*
// @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @require https://update.greasyfork.org/scripts/24851/WazeWrap.js
// @author dBsooner
// @license MIT/BSD/X11
// @connect greasyfork.org
Expand Down Expand Up @@ -277,6 +277,87 @@
log(message, data);
}

function formatXhrError(res, label = 'Request error') {
if (!res)
return label;
const details = [];
if (typeof res.status !== 'undefined')
details.push(`status ${res.status}`);
if (res.statusText)
details.push(res.statusText);
if (res.finalUrl)
details.push(res.finalUrl);
if (res.responseText) {
try {
const parsed = JSON.parse(res.responseText);
if (parsed?.error?.message)
details.push(parsed.error.message);
}
catch (e) {
// Ignore JSON parsing issues and keep collected request metadata only.
}
}
return `${label}${details.length > 0 ? `: ${details.join(' | ')}` : ''}`;
}

function requestWithReferrerFallback(options) {
const { url, method = 'GET', headers = {}, onload, onerror } = options;
const shouldFallback = (res) => {
const body = res?.responseText || '';
return (res?.status === 403) && (/referer\s*<empty>/i.test(body) || /requests from referer/i.test(body));
};
const fetchFallback = async (originalRes, routeTo) => {
try {
const pageWindow = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
// Referer is a forbidden header in fetch; use page context to inherit normal browser referrer behavior.
const safeHeaders = { ...headers };
delete safeHeaders.Referer;
delete safeHeaders.referer;
const response = await pageWindow.fetch(url, {
method,
headers: safeHeaders,
credentials: 'omit'
});
const responseText = await response.text();
const fallbackRes = {
status: response.status,
statusText: response.statusText,
responseText,
finalUrl: response.url || url
};
onload(fallbackRes);
}
catch (fetchErr) {
const fallbackErr = {
status: 0,
statusText: fetchErr?.message || 'fetch failed',
finalUrl: url,
responseText: ''
};
if (typeof onerror === 'function') {
onerror(fallbackErr);
} else if (typeof routeTo === 'function') {
routeTo(fallbackErr);
}
}
};
GM_xmlhttpRequest({
url,
method,
headers,
onload(res) {
if (shouldFallback(res)) {
fetchFallback(res, onerror);
return;
}
onload(res);
},
onerror(res) {
fetchFallback(res, onerror);
}
});
}

function dynamicSort(property) {
let sortOrder = 1;
if (property[0] === '-') {
Expand Down Expand Up @@ -4022,7 +4103,7 @@
commentListIdx = (isNaN(commentListIdx)) ? _settings.commentList : commentListIdx;
const commentListInfo = getCommentListInfo(commentListIdx);
logDebug(`Beginning comment list async for comment list: ${commentListInfo.name}`);
GM_xmlhttpRequest({
requestWithReferrerFallback({
url: `https://sheets.googleapis.com/v4/spreadsheets/${((commentListIdx === 1001) ? _settings.customSsId : dec(_URCE_SPREADSHEET_ID))}/values/${commentListInfo.gSheetRange}?key=${dec(_URCE_API_KEY)}`,
headers: { 'Content-Type': 'application/json', Referer: 'https://www.waze.com' },
method: 'GET',
Expand Down Expand Up @@ -4407,8 +4488,19 @@

function handleError(err) {
const divElemRoot = createElem('div', { class: 'URCE-divLoading' });
if (err.message?.includes('|') > -1) {
const [reason, version] = err.message.split('|');
let errMessage = (typeof err === 'string') ? err : (err?.message || '');
if (!errMessage && (typeof err === 'object')) {
try {
errMessage = JSON.stringify(err);
}
catch (e) {
errMessage = String(err);
}
}
if (errMessage === '[object Object]')
errMessage = formatXhrError(err, 'Unexpected error');
if (errMessage.includes('|')) {
const [reason, version] = errMessage.split('|');
if ((reason === 'updateRequired') || (reason === 'spreadsheetUpdateRequired')) {
const scriptLink = createElem('a', {
href: _IS_BETA_VERSION ? dec(_BETA_DL_URL) : _PROD_DL_URL, target: '_blank', textContent: _IS_BETA_VERSION ? dec(_BETA_DL_URL) : _PROD_DL_URL
Comment on lines +4502 to 4506

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleError now branches on errMessage.includes('|'), but only renders UI inside that branch when the prefix is updateRequired| or spreadsheetUpdateRequired|. Since newly introduced messages (e.g., formatXhrError uses | separators) can contain |, this can produce an empty error UI. Make the condition more specific (e.g., check startsWith('updateRequired|')/startsWith('spreadsheetUpdateRequired|')), or fall back to the generic error rendering when the split reason is unrecognized.

Copilot uses AI. Check for mistakes.
Expand All @@ -4427,6 +4519,10 @@
}
else {
divElemRoot.appendChild(createElem('div', { textContent: (err.commentList === 1001) ? I18n.t('urce.prompts.CustomGSheetLoadError') : I18n.t('urce.common.ErrorGeneric') }));
if (errMessage.length > 0) {
divElemRoot.appendChild(createElem('br'));
divElemRoot.appendChild(createElem('div', { textContent: `Details: ${errMessage}` }));
}
}
logError(divElemRoot.textContent);
_commentListLoaded = false;
Expand Down Expand Up @@ -5815,7 +5911,7 @@
resolve();
}
};
GM_xmlhttpRequest({
requestWithReferrerFallback({
url: `https://sheets.googleapis.com/v4/spreadsheets/${dec(_URCE_SPREADSHEET_ID)}/values/CommentLists!A3:G?key=${dec(_URCE_API_KEY)}`,
headers: { 'Content-Type': 'application/json', Referer: 'https://www.waze.com' },
method: 'GET',
Expand Down Expand Up @@ -5868,12 +5964,12 @@
}
}
else {
errorText = errorText || res;
errorText = errorText || formatXhrError(res, 'Comment list request failed');
}
postProcess(errorText);
},
onerror(res) {
postProcess(`xmlhttpRequest error: ${JSON.stringify(res)}`);
postProcess(formatXhrError(res, 'Comment list request failed'));
}
});
});
Expand All @@ -5883,12 +5979,11 @@
return new Promise((resolve, reject) => {
logDebug('Initializing auto switch setup.');
const postProcess = function (errorText) {
if (!errorText || (errorText && _STATIC_ONLY_USERS.includes(W.loginManager.user.getUsername())))
resolve();
else
reject(new Error(errorText));
if (errorText)
logWarning(`Auto-switch setup unavailable: ${errorText}`);
resolve();
};
GM_xmlhttpRequest({
requestWithReferrerFallback({
url: `https://sheets.googleapis.com/v4/spreadsheets/${dec(_URCE_SPREADSHEET_ID)}/values/CommentLists_AutoSwitch!A3:ZZ?majorDimension=COLUMNS&key=${dec(_URCE_API_KEY)}`,
headers: { 'Content-Type': 'application/json', Referer: 'https://www.waze.com' },
method: 'GET',
Expand Down Expand Up @@ -5927,12 +6022,12 @@
}
}
else {
errorText = errorText || res;
errorText = errorText || formatXhrError(res, 'Auto-switch request failed');
}
postProcess(errorText);
},
onerror(res) {
postProcess(`xmlhttpRequest error: ${JSON.stringify(res)}`);
postProcess(formatXhrError(res, 'Auto-switch request failed'));
}
});
});
Expand All @@ -5942,12 +6037,11 @@
return new Promise((resolve, reject) => {
logDebug('Initializing restrictions.');
const postProcess = function (errorText) {
if (!errorText || (errorText && _STATIC_ONLY_USERS.includes(W.loginManager.user.getUsername())))
resolve();
else
reject(new Error(errorText));
if (errorText)
logWarning(`Restrictions setup unavailable: ${errorText}`);
resolve();
};
GM_xmlhttpRequest({
requestWithReferrerFallback({
url: `https://sheets.googleapis.com/v4/spreadsheets/${dec(_URCE_SPREADSHEET_ID)}/values/Restrictions!A3:ZZ?majorDimension=COLUMNS&key=${dec(_URCE_API_KEY)}`,
headers: { 'Content-Type': 'application/json', Referer: 'https://www.waze.com' },
method: 'GET',
Expand Down Expand Up @@ -5996,12 +6090,12 @@
}
}
else {
errorText = errorText || res;
errorText = errorText || formatXhrError(res, 'Restrictions request failed');
}
postProcess(errorText);
},
onerror(res) {
postProcess(`xmlhttpRequest error: ${JSON.stringify(res)}`);
postProcess(formatXhrError(res, 'Restrictions request failed'));
}
});
});
Expand Down Expand Up @@ -6203,7 +6297,7 @@
});
}
/* END FIX */
GM_xmlhttpRequest({
requestWithReferrerFallback({
url: `https://sheets.googleapis.com/v4/spreadsheets/${dec(_URCE_SPREADSHEET_ID)}/values/Script_Translations!A3:AA?key=${dec(_URCE_API_KEY)}`,
headers: { 'Content-Type': 'application/json', Referer: 'https://www.waze.com' },
method: 'GET',
Expand Down Expand Up @@ -6774,12 +6868,12 @@
_needTranslation = true;
}
else {
errorText = errorText || res;
errorText = errorText || formatXhrError(res, 'Translations request failed');
}
postProcess(errorText);
},
onerror(res) {
postProcess(`xmlhttpRequest error: ${JSON.stringify(res)}`);
postProcess(formatXhrError(res, 'Translations request failed'));
}
});
});
Expand Down