MediaWiki:Gadget-wikisync-core.js: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
(Created page with "→* * WikiSync: * - Utilises our WikiSync API, with data provided by users via RuneLite. * - Adds the ability to check a user's completed quests. * * Slightly adapted from https://runescape.wiki/w/MediaWiki:Gadget-questchecker-core.js * * @author Jayden * @author Andmcadams * @author Jakesterwars * @author Cook Me Plox * @author Lezed1 * @author Haidro: var CLASSES = { QC_ACTIVE: "qc-active", QC_INPUT: "qc-input", QC_ICON: "rs-qc-icon", }; var END...") |
No edit summary |
||
Line 1: | Line 1: | ||
"use strict"; |
|||
/** |
/** |
||
* WikiSync: |
* WikiSync: |
||
Line 17: | Line 19: | ||
QC_ACTIVE: "qc-active", |
QC_ACTIVE: "qc-active", |
||
QC_INPUT: "qc-input", |
QC_INPUT: "qc-input", |
||
QC_ICON: "rs-qc-icon" |
QC_ICON: "rs-qc-icon" |
||
}; |
}; |
||
var ENDPOINTS = { |
var ENDPOINTS = { |
||
osrs: "https://sync.runescape.wiki/runelite/player/username/STANDARD", |
osrs: "https://sync.runescape.wiki/runelite/player/username/STANDARD", |
||
shatteredrelics: "https://sync.runescape.wiki/runelite/player/username/SHATTERED_RELICS_LEAGUE" //use actual url |
|||
shatteredrelics: |
|||
"https://sync.runescape.wiki/runelite/player/username/SHATTERED_RELICS_LEAGUE", //use actual url |
|||
}; |
}; |
||
var questCorrections = { |
var questCorrections = { |
||
// Add corrections for API quest names -> wiki names here. |
// Add corrections for API quest names -> wiki names here. |
||
// API quest name is the key and the wiki page name is the value. |
// API quest name is the key and the wiki page name is the value. |
||
"Desert Treasure II - The Fallen Empire": "Desert Treasure II", |
"Desert Treasure II - The Fallen Empire": "Desert Treasure II", |
||
"Recipe for Disaster - Another Cook's Quest" |
"Recipe for Disaster - Another Cook's Quest": "Recipe for Disaster/Another Cook's Quest", |
||
"Recipe for Disaster - Culinaromancer" |
"Recipe for Disaster - Culinaromancer": "Recipe for Disaster/Defeating the Culinaromancer", |
||
"Recipe for Disaster - Mountain Dwarf" |
"Recipe for Disaster - Mountain Dwarf": "Recipe for Disaster/Freeing the Mountain Dwarf", |
||
"Recipe for Disaster - Wartface & Bentnoze" |
"Recipe for Disaster - Wartface & Bentnoze": "Recipe for Disaster/Freeing the Goblin generals", |
||
"Recipe for Disaster - Pirate Pete" |
"Recipe for Disaster - Pirate Pete": "Recipe for Disaster/Freeing Pirate Pete", |
||
"Recipe for Disaster - Lumbridge Guide" |
"Recipe for Disaster - Lumbridge Guide": "Recipe for Disaster/Freeing the Lumbridge Guide", |
||
"Recipe for Disaster - Evil Dave" |
"Recipe for Disaster - Evil Dave": "Recipe for Disaster/Freeing Evil Dave", |
||
"Recipe for Disaster - King Awowogei" |
"Recipe for Disaster - King Awowogei": "Recipe for Disaster/Freeing King Awowogei", |
||
"Recipe for Disaster - Sir Amik Varze" |
"Recipe for Disaster - Sir Amik Varze": "Recipe for Disaster/Freeing Sir Amik Varze", |
||
"Recipe for Disaster - Skrach Uglogwee" |
"Recipe for Disaster - Skrach Uglogwee": "Recipe for Disaster/Freeing Skrach Uglogwee" |
||
}, |
}, |
||
icons = { |
icons = { |
||
yes: ' <span class="' + CLASSES.QC_ICON + '"><img class="qc-complete" src="//oldschool.runescape.wiki/images/Yes_check.svg?00000" width="15px" ></span>', |
yes: ' <span class="' + CLASSES.QC_ICON + '"><img class="qc-complete" src="//oldschool.runescape.wiki/images/Yes_check.svg?00000" width="15px" ></span>', |
||
no: ' <span class="' + CLASSES.QC_ICON + '"><img class="qc-not-started" src="//oldschool.runescape.wiki/images/X_mark.svg?00000" width="13px" ></span>' |
no: ' <span class="' + CLASSES.QC_ICON + '"><img class="qc-not-started" src="//oldschool.runescape.wiki/images/X_mark.svg?00000" width="13px" ></span>' |
||
}; |
}; |
||
var wikisync = { |
var wikisync = { |
||
/** |
/** |
||
* Startup method |
* Startup method |
||
*/ |
*/ |
||
init: function () { |
init: function init() { |
||
wikisync.createFields(); |
wikisync.createFields(); |
||
}, |
}, |
||
setCheckboxText: function setCheckboxText(text) { |
|||
$(".rs-wikisync-hide-completed .oo-ui-labelElement-label").each(function () { |
|||
setCheckboxText: function (text) { |
|||
$(this).text(text); |
|||
$(".rs-wikisync-hide-completed .oo-ui-labelElement-label").each( |
|||
}); |
|||
$(this).text(text); |
|||
} |
|||
); |
|||
}, |
}, |
||
hideCompletedEntries: function hideCompletedEntries() { |
|||
hideCompletedEntries: function () { |
|||
var selected = wikisync.hideCompletedCheckbox.isSelected(); |
var selected = wikisync.hideCompletedCheckbox.isSelected(); |
||
if (selected) { |
if (selected) { |
||
Line 69: | Line 62: | ||
} |
} |
||
}, |
}, |
||
/** |
/** |
||
* Creates the input fields for the user's RSN |
* Creates the input fields for the user's RSN |
||
*/ |
*/ |
||
createFields: function () { |
createFields: function createFields() { |
||
var name; |
var name; |
||
if (rs.hasLocalStorage() === true) { |
if (rs.hasLocalStorage() === true) { |
||
$.removeCookie("RSN", { |
$.removeCookie("RSN", { |
||
path: "/" |
|||
}); // remove any existing cookies using jQuery, will return false if it doesn't exist so it's fine |
|||
name = localStorage.getItem("rsn"); |
name = localStorage.getItem("rsn"); |
||
} else { |
} else { |
||
name = wikisync.getCookie("RSN"); |
name = wikisync.getCookie("RSN"); |
||
} |
} |
||
var gamemode = "osrs"; |
var gamemode = "osrs"; |
||
$("." + CLASSES.QC_INPUT).each(function () { |
$("." + CLASSES.QC_INPUT).each(function () { |
||
var input1 = new OO.ui.TextInputWidget({ |
var input1 = new OO.ui.TextInputWidget({ |
||
placeholder: "Display name", |
placeholder: "Display name", |
||
id: "rs-qc-rsn" |
id: "rs-qc-rsn" |
||
}); |
}); |
||
if (name) { |
if (name) { |
||
// Set input to cookie/localStorage value. |
// Set input to cookie/localStorage value. |
||
input1.setValue(name); |
input1.setValue(name); |
||
} |
} |
||
var button1 = new OO.ui.ButtonInputWidget({ |
var button1 = new OO.ui.ButtonInputWidget({ |
||
label: new OO.ui.HtmlSnippet( |
label: new OO.ui.HtmlSnippet('<img src="' + rs.getFileURLCached("RuneLite icon.png") + '" width=' + '"20px" />' + " Look up"), |
||
'<img src="' + |
|||
rs.getFileURLCached("RuneLite icon.png") + |
|||
'" width=' + |
|||
'"20px" />' + |
|||
" Look up" |
|||
), |
|||
title: "Look up player data using RuneLite", |
title: "Look up player data using RuneLite", |
||
flags: ["primary", "progressive"], |
flags: ["primary", "progressive"], |
||
classes: ["wikisync-lookup-button"] |
classes: ["wikisync-lookup-button"] |
||
}); |
}); |
||
var leagueOnly = $(this).hasClass("league-only"); |
var leagueOnly = $(this).hasClass("league-only"); |
||
if (leagueOnly) { |
if (leagueOnly) { |
||
gamemode = "shatteredrelics"; |
gamemode = "shatteredrelics"; |
||
} |
} |
||
var button1action = function button1action() { |
|||
var button1action = function () { |
|||
if (rs.hasLocalStorage() === true) { |
if (rs.hasLocalStorage() === true) { |
||
localStorage.setItem("rsn", input1.value); // save in localStorage |
localStorage.setItem("rsn", input1.value); // save in localStorage |
||
Line 123: | Line 105: | ||
button1.on("click", button1action); |
button1.on("click", button1action); |
||
input1.on("enter", button1action); |
input1.on("enter", button1action); |
||
var helpModalBtn = new OO.ui.ButtonWidget({ |
var helpModalBtn = new OO.ui.ButtonWidget({ |
||
label: "Learn how to enable WikiSync", |
label: "Learn how to enable WikiSync", |
||
href: "/w/RuneScape:WikiSync" |
href: "/w/RuneScape:WikiSync" |
||
}); |
}); |
||
var hideCompleted = false; |
var hideCompleted = false; |
||
if (rs.hasLocalStorage()) { |
if (rs.hasLocalStorage()) { |
||
Line 136: | Line 116: | ||
} |
} |
||
wikisync.hideCompletedCheckbox = new OO.ui.CheckboxInputWidget({ |
wikisync.hideCompletedCheckbox = new OO.ui.CheckboxInputWidget({ |
||
selected: hideCompleted |
selected: hideCompleted |
||
}); |
}); |
||
wikisync.hideCompletedCheckbox.on("change", function () { |
wikisync.hideCompletedCheckbox.on("change", function () { |
||
Line 145: | Line 125: | ||
$(".wikisync-completed").toggle(!selected); |
$(".wikisync-completed").toggle(!selected); |
||
}); |
}); |
||
var fieldset = new OO.ui.FieldsetLayout({ |
var fieldset = new OO.ui.FieldsetLayout({ |
||
id: "rs-qc-form" |
id: "rs-qc-form" |
||
}); |
}); |
||
var fieldSetItems = [new OO.ui.FieldLayout(input1, { |
|||
label: "Username:", |
|||
align: "inline" |
|||
]; |
})]; |
||
fieldSetItems.push(button1); |
fieldSetItems.push(button1); |
||
fieldset.addItems([ |
fieldset.addItems([new OO.ui.HorizontalLayout({ |
||
items: fieldSetItems |
|||
}), new OO.ui.FieldLayout(helpModalBtn, { |
|||
items: fieldSetItems, |
|||
label: "No data found. To use this, enable the WikiSync plugin in RuneLite.", |
|||
}), |
|||
align: "inline", |
|||
classes: ["rs-wikisync-help"] |
|||
}), new OO.ui.LabelWidget({ |
|||
"No data found. To use this, enable the WikiSync plugin in RuneLite.", |
|||
label: "Missing some data from RuneLite for this page. Please log in to the game to re-sync.", |
|||
align: "inline", |
|||
classes: ["rs-wikisync-missingdata"] |
|||
}), new OO.ui.FieldLayout(wikisync.hideCompletedCheckbox, { |
|||
}), |
|||
label: "Hide completed", |
|||
align: "inline", |
|||
classes: ["rs-wikisync-hide-completed"] |
|||
"Missing some data from RuneLite for this page. Please log in to the game to re-sync.", |
|||
})]); |
|||
classes: ["rs-wikisync-missingdata"], |
|||
}), |
|||
new OO.ui.FieldLayout(wikisync.hideCompletedCheckbox, { |
|||
label: "Hide completed", |
|||
align: "inline", |
|||
classes: ["rs-wikisync-hide-completed"], |
|||
}), |
|||
]); |
|||
if ($(this).hasClass("lighttable")) { |
if ($(this).hasClass("lighttable")) { |
||
// If it's a lighttable, insert the fieldset before the table |
// If it's a lighttable, insert the fieldset before the table |
||
Line 192: | Line 162: | ||
} |
} |
||
}); |
}); |
||
if (name) { |
if (name) { |
||
// If there is a saved name, load the data for it. |
// If there is a saved name, load the data for it. |
||
Line 198: | Line 167: | ||
} |
} |
||
}, |
}, |
||
/** |
/** |
||
* Updates the status text |
* Updates the status text |
||
*/ |
*/ |
||
updateStatus: function (text) { |
updateStatus: function updateStatus(text) { |
||
mw.notify(text, { |
mw.notify(text, { |
||
tag: "wikisync" |
|||
}); |
|||
}, |
}, |
||
/** |
/** |
||
* Sets a cookie |
* Sets a cookie |
||
*/ |
*/ |
||
setCookie: function (name, value, days) { |
setCookie: function setCookie(name, value, days) { |
||
var expires = ""; |
var expires = ""; |
||
if (days) { |
if (days) { |
||
Line 218: | Line 187: | ||
document.cookie = name + "=" + (value || "") + expires + "; path=/"; |
document.cookie = name + "=" + (value || "") + expires + "; path=/"; |
||
}, |
}, |
||
/** |
/** |
||
* Returns the value of a cookie, or null if it doesn't exist |
* Returns the value of a cookie, or null if it doesn't exist |
||
*/ |
*/ |
||
getCookie: function (name) { |
getCookie: function getCookie(name) { |
||
var cookie = new RegExp( |
var cookie = new RegExp("^(?:.*;)?\\s*" + name + "\\s*=\\s*([^;]+)(?:.*)?$"), |
||
"^(?:.*;)?\\s*" + name + "\\s*=\\s*([^;]+)(?:.*)?$" |
|||
), |
|||
match = document.cookie.match(cookie); |
match = document.cookie.match(cookie); |
||
if (match !== null) { |
if (match !== null) { |
||
return match[1]; |
return match[1]; |
||
Line 234: | Line 199: | ||
} |
} |
||
}, |
}, |
||
/** |
/** |
||
* Load data |
* Load data |
||
*/ |
*/ |
||
loadData: function (rsn, gamemode) { |
loadData: function loadData(rsn, gamemode) { |
||
if (!rsn) { |
if (!rsn) { |
||
wikisync.updateStatus("Invalid RSN"); |
wikisync.updateStatus("Invalid RSN"); |
||
return; |
return; |
||
} |
} |
||
var endpoint = ENDPOINTS[gamemode || "osrs"] || ENDPOINTS.osrs; |
var endpoint = ENDPOINTS[gamemode || "osrs"] || ENDPOINTS.osrs; |
||
// Hide help text if it is showing. |
// Hide help text if it is showing. |
||
Line 249: | Line 212: | ||
$(".rs-wikisync-missingdata").hide(); |
$(".rs-wikisync-missingdata").hide(); |
||
$(".wikisync-success").remove(); |
$(".wikisync-success").remove(); |
||
$.ajax({ |
$.ajax({ |
||
// Get the quest data |
// Get the quest data |
||
Line 255: | Line 217: | ||
url: endpoint.replace("username", rsn), |
url: endpoint.replace("username", rsn), |
||
dataType: "json", |
dataType: "json", |
||
success: function (msg) { |
success: function success(msg) { |
||
var userQuests = {}; |
var userQuests = {}; |
||
Object.entries(msg.quests).forEach(function (q) { |
Object.entries(msg.quests).forEach(function (q) { |
||
Line 277: | Line 239: | ||
$(".wikisync-completed").show(); |
$(".wikisync-completed").show(); |
||
$(".wikisync-completed").removeClass("wikisync-completed"); |
$(".wikisync-completed").removeClass("wikisync-completed"); |
||
$("<img>").attr("src", "//oldschool.runescape.wiki/images/f/fb/Yes_check.svg?00000").addClass("wikisync-success").css("width", "20px").css("height", "20px").css("position", "relative").insertAfter(".wikisync-lookup-button"); |
|||
$("<img>") |
|||
var hasAllData = [wikisync.addQuestIcons(userQuests), wikisync.addQuestTable(userQuests, userSkills, msg.achievement_diaries), wikisync.addDiaryTable(msg.achievement_diaries), wikisync.addSkillTable(userSkills), wikisync.addSkillIcons(userSkills), wikisync.addMusicTracks(msg.music_tracks), wikisync.addCombatAchievementTasks(msg.combat_achievements)].every(function (result) { |
|||
.attr( |
|||
"src", |
|||
"//oldschool.runescape.wiki/images/f/fb/Yes_check.svg?00000" |
|||
) |
|||
.addClass("wikisync-success") |
|||
.css("width", "20px") |
|||
.css("height", "20px") |
|||
.css("position", "relative") |
|||
.insertAfter(".wikisync-lookup-button"); |
|||
var hasAllData = [ |
|||
wikisync.addQuestIcons(userQuests), |
|||
wikisync.addQuestTable( |
|||
userQuests, |
|||
userSkills, |
|||
msg.achievement_diaries |
|||
), |
|||
wikisync.addDiaryTable(msg.achievement_diaries), |
|||
wikisync.addSkillTable(userSkills), |
|||
wikisync.addSkillIcons(userSkills), |
|||
wikisync.addMusicTracks(msg.music_tracks), |
|||
wikisync.addCombatAchievementTasks(msg.combat_achievements), |
|||
].every(function (result) { |
|||
return result; |
return result; |
||
}); |
}); |
||
if (!hasAllData) { |
if (!hasAllData) { |
||
$(".rs-wikisync-missingdata").show(); |
$(".rs-wikisync-missingdata").show(); |
||
} |
} |
||
}, |
}, |
||
error: function (req) { |
error: function error(req) { |
||
$("." + CLASSES.QC_ICON).remove(); |
$("." + CLASSES.QC_ICON).remove(); |
||
wikisync.setCheckboxText("Hide completed"); |
wikisync.setCheckboxText("Hide completed"); |
||
if (req.responseJSON && req.responseJSON.code && req.responseJSON.code === "NO_USER_DATA") { |
|||
if ( |
|||
req.responseJSON && |
|||
req.responseJSON.code && |
|||
req.responseJSON.code === "NO_USER_DATA" |
|||
) { |
|||
$(".rs-wikisync-help").show(); |
$(".rs-wikisync-help").show(); |
||
} else { |
} else { |
||
wikisync.updateStatus("There was a problem loading data for " + rsn); |
wikisync.updateStatus("There was a problem loading data for " + rsn); |
||
} |
} |
||
} |
} |
||
}); |
}); |
||
}, |
}, |
||
/** |
/** |
||
* Clicks the Combat Achievement rows |
* Clicks the Combat Achievement rows |
||
*/ |
*/ |
||
addCombatAchievementTasks: function (combatAchievements) { |
addCombatAchievementTasks: function addCombatAchievementTasks(combatAchievements) { |
||
var combatAchievementTable = $('table.' + CLASSES.QC_ACTIVE + '.ca-tasks'); |
var combatAchievementTable = $('table.' + CLASSES.QC_ACTIVE + '.ca-tasks'); |
||
if (combatAchievementTable.length === 0) { |
if (combatAchievementTable.length === 0) { |
||
Line 333: | Line 267: | ||
return true; |
return true; |
||
} |
} |
||
if (combatAchievementTable === null) { |
if (combatAchievementTable === null) { |
||
return false; |
return false; |
||
} |
} |
||
var seen = {}; |
var seen = {}; |
||
combatAchievements.forEach(function (taskId) { |
combatAchievements.forEach(function (taskId) { |
||
Line 343: | Line 275: | ||
}); |
}); |
||
combatAchievementTable.each(function () { |
combatAchievementTable.each(function () { |
||
$(this) |
$(this).find("tr[data-ca-task-id]").each(function () { |
||
. |
var task_id = $(this).data("ca-task-id"); |
||
if (!!seen[task_id] !== $(this).hasClass("highlight-on")) { |
|||
$(this).click(); |
|||
} |
|||
if (!!seen[task_id] !== $(this).hasClass("highlight-on")) { |
|||
if (seen[task_id]) { |
|||
$(this).addClass("wikisync-completed"); |
|||
} |
|||
}); |
|||
$(this).addClass("wikisync-completed"); |
|||
} |
|||
}); |
|||
}); |
}); |
||
return true; |
return true; |
||
}, |
}, |
||
/** |
/** |
||
* Clicks the music track rows |
* Clicks the music track rows |
||
*/ |
*/ |
||
addMusicTracks: function (musicTracks) { |
addMusicTracks: function addMusicTracks(musicTracks) { |
||
var musicTable = $("table." + CLASSES.QC_ACTIVE + ".music-tracks"); |
var musicTable = $("table." + CLASSES.QC_ACTIVE + ".music-tracks"); |
||
if (musicTable.length === 0) { |
if (musicTable.length === 0) { |
||
Line 368: | Line 296: | ||
return true; |
return true; |
||
} |
} |
||
if (musicTracks === null) { |
if (musicTracks === null) { |
||
// Missing data |
// Missing data |
||
return false; |
return false; |
||
} |
} |
||
var total = 0; |
var total = 0; |
||
var completed = 0; |
var completed = 0; |
||
musicTable.each(function () { |
musicTable.each(function () { |
||
$(this).find("tr[data-music-track-name]").each(function () { |
|||
$(this) |
|||
. |
var music_track_name = $(this).data("music-track-name"); |
||
if (!!musicTracks[music_track_name] !== $(this).hasClass("highlight-on")) { |
|||
.each(function () { |
|||
$(this).click(); |
|||
} |
|||
if (!!musicTracks[music_track_name] !== $(this).hasClass("highlight-on")) { |
|||
if (musicTracks[music_track_name]) { |
|||
$(this).click(); |
|||
$(this).addClass("wikisync-completed"); |
|||
completed++; |
|||
} |
|||
$(this).addClass("wikisync-completed"); |
|||
total++; |
|||
}); |
|||
total++; |
|||
}); |
|||
}); |
}); |
||
wikisync.setCheckboxText( |
wikisync.setCheckboxText("Hide unlocked tracks (" + completed + "/" + total + " unlocked)"); |
||
"Hide unlocked tracks (" + completed + "/" + total + " unlocked)" |
|||
); |
|||
wikisync.hideCompletedEntries(); |
wikisync.hideCompletedEntries(); |
||
return true; |
return true; |
||
}, |
}, |
||
/** |
/** |
||
* Append a checkmark/X icon to `element`. |
* Append a checkmark/X icon to `element`. |
||
*/ |
*/ |
||
append_icon: function (element, completed) { |
append_icon: function append_icon(element, completed) { |
||
if (completed) { |
if (completed) { |
||
$(element).append(icons.yes); |
$(element).append(icons.yes); |
||
Line 408: | Line 329: | ||
} |
} |
||
}, |
}, |
||
/** |
/** |
||
* Clicks the rows in a table of question and diary tiers. Also appends icons to rows dedicated to skill training |
* Clicks the rows in a table of question and diary tiers. Also appends icons to rows dedicated to skill training |
||
*/ |
*/ |
||
addQuestTable: function (quests, skills, achievementDiaries) { |
addQuestTable: function addQuestTable(quests, skills, achievementDiaries) { |
||
function splitOnLastOccurence(str, splitOn) { |
function splitOnLastOccurence(str, splitOn) { |
||
var index = str.lastIndexOf(splitOn); |
var index = str.lastIndexOf(splitOn); |
||
return { |
|||
return { before: str.slice(0, index), after: str.slice(index + 1) }; |
|||
before: str.slice(0, index), |
|||
after: str.slice(index + 1) |
|||
}; |
|||
} |
} |
||
Line 422: | Line 345: | ||
var rowID = $(this).data("rowid"); |
var rowID = $(this).data("rowid"); |
||
var isAchievementDiary = rowID.includes("Diary#"); |
var isAchievementDiary = rowID.includes("Diary#"); |
||
if (isAchievementDiary) { |
if (isAchievementDiary) { |
||
// Achievement diary rowIDs are formatted as "$NAME Diary#$TIER", where "$NAME" may contain spaces. |
// Achievement diary rowIDs are formatted as "$NAME Diary#$TIER", where "$NAME" may contain spaces. |
||
Line 428: | Line 350: | ||
var diaryName = splitOnLastOccurence(rowID, " ").before; |
var diaryName = splitOnLastOccurence(rowID, " ").before; |
||
var diaryTier = splitOnLastOccurence(rowID, "#").after; |
var diaryTier = splitOnLastOccurence(rowID, "#").after; |
||
if (diaryName in achievementDiaries && diaryTier in achievementDiaries[diaryName] && "complete" in achievementDiaries[diaryName][diaryTier]) { |
|||
if ( |
|||
var diaryCompleted = achievementDiaries[diaryName][diaryTier].complete; |
|||
diaryName in achievementDiaries && |
|||
diaryTier in achievementDiaries[diaryName] && |
|||
"complete" in achievementDiaries[diaryName][diaryTier] |
|||
) { |
|||
var diaryCompleted = |
|||
achievementDiaries[diaryName][diaryTier].complete; |
|||
if (diaryCompleted !== null) { |
if (diaryCompleted !== null) { |
||
if (diaryCompleted !== $(this).hasClass("highlight-on")) { |
if (diaryCompleted !== $(this).hasClass("highlight-on")) { |
||
Line 453: | Line 370: | ||
// Skill training complete |
// Skill training complete |
||
$("table." + CLASSES.QC_ACTIVE + ".oqg-table tr[data-skill][data-skill-level]").each(function () { |
|||
$( |
|||
"table." + CLASSES.QC_ACTIVE + ".oqg-table tr[data-skill][data-skill-level]" |
|||
).each(function () { |
|||
var skillName = $(this).data("skill"); |
var skillName = $(this).data("skill"); |
||
skillName = skillName.charAt(0).toUpperCase() + skillName.slice(1); |
skillName = skillName.charAt(0).toUpperCase() + skillName.slice(1); |
||
Line 464: | Line 379: | ||
return true; |
return true; |
||
}, |
}, |
||
// Clicks cells/rows in a table based on skill levels. |
// Clicks cells/rows in a table based on skill levels. |
||
addSkillTable: function (skills) { |
addSkillTable: function addSkillTable(skills) { |
||
$("table." + CLASSES.QC_ACTIVE + ".skill-table [data-skill][data-skill-level]").each(function () { |
|||
$( |
|||
"table." + CLASSES.QC_ACTIVE + ".skill-table [data-skill][data-skill-level]" |
|||
).each(function () { |
|||
var skillName = $(this).data("skill"); |
var skillName = $(this).data("skill"); |
||
var skillLevel = $(this).data("skill-level"); |
var skillLevel = $(this).data("skill-level"); |
||
Line 479: | Line 391: | ||
return true; |
return true; |
||
}, |
}, |
||
// Clicks rows in a table based on achievement diary task completion |
// Clicks rows in a table based on achievement diary task completion |
||
addDiaryTable: function (achievementDiaries) { |
addDiaryTable: function addDiaryTable(achievementDiaries) { |
||
var hasAllData = true; |
var hasAllData = true; |
||
$("table." + CLASSES.QC_ACTIVE + ".diary-table[data-diary-name][data-diary-tier]").each(function () { |
|||
$( |
|||
"table." + CLASSES.QC_ACTIVE + ".diary-table[data-diary-name][data-diary-tier]" |
|||
).each(function () { |
|||
var task_index = -1; |
var task_index = -1; |
||
var diaryName = $(this).data("diary-name"); |
var diaryName = $(this).data("diary-name"); |
||
var diaryTier = $(this).data("diary-tier"); |
var diaryTier = $(this).data("diary-tier"); |
||
$(this) |
$(this).find("tr").each(function () { |
||
if (task_index < 0) { |
|||
task_index += 1; |
|||
return; |
|||
} |
|||
if (diaryName in achievementDiaries && diaryTier in achievementDiaries[diaryName] && achievementDiaries[diaryName][diaryTier].tasks.length > task_index) { |
|||
return; |
|||
var task_completed = achievementDiaries[diaryName][diaryTier].tasks[task_index]; |
|||
} |
|||
if ( |
if (task_completed !== null) { |
||
if (task_completed !== $(this).hasClass("highlight-on")) { |
|||
diaryName in achievementDiaries && |
|||
$(this).click(); |
|||
achievementDiaries[diaryName][diaryTier].tasks.length > task_index |
|||
) { |
|||
var task_completed = |
|||
achievementDiaries[diaryName][diaryTier].tasks[task_index]; |
|||
if (task_completed !== null) { |
|||
if (task_completed !== $(this).hasClass("highlight-on")) { |
|||
$(this).click(); |
|||
} |
|||
} else { |
|||
hasAllData = false; |
|||
} |
} |
||
} else { |
|||
hasAllData = false; |
|||
} |
} |
||
} |
|||
task_index += 1; |
|||
}); |
|||
}); |
}); |
||
return hasAllData; |
return hasAllData; |
||
}, |
}, |
||
/** |
/** |
||
* Adds the icons next to respective quests |
* Adds the icons next to respective quests |
||
*/ |
*/ |
||
addQuestIcons: function (quests) { |
addQuestIcons: function addQuestIcons(quests) { |
||
$("." + CLASSES.QC_ACTIVE + " a").each(function () { |
$("." + CLASSES.QC_ACTIVE + " a").each(function () { |
||
if ($(this).html().toLowerCase() != "expand" || $(this).html().toLowerCase() != "collapse") { |
|||
if ( |
|||
$(this).html().toLowerCase() != "expand" || |
|||
$(this).html().toLowerCase() != "collapse" |
|||
) { |
|||
var questTitle = $(this).text().trim(); |
var questTitle = $(this).text().trim(); |
||
if (questTitle in quests) { |
if (questTitle in quests) { |
||
Line 535: | Line 432: | ||
return true; |
return true; |
||
}, |
}, |
||
/** |
/** |
||
* Adds the icons next to respective skills |
* Adds the icons next to respective skills |
||
*/ |
*/ |
||
addSkillIcons: function (userLevels) { |
addSkillIcons: function addSkillIcons(userLevels) { |
||
$("." + CLASSES.QC_ACTIVE + " .scp").each(function () { |
$("." + CLASSES.QC_ACTIVE + " .scp").each(function () { |
||
var level = $(this).data("level"); |
var level = $(this).data("level"); |
||
Line 549: | Line 445: | ||
}); |
}); |
||
return true; |
return true; |
||
} |
} |
||
}; |
}; |
||
$(wikisync.init); |
$(wikisync.init); |
Latest revision as of 12:06, 20 October 2024
"use strict";
/**
* WikiSync:
* - Utilises our WikiSync API, with data provided by users via RuneLite.
* - Adds the ability to check a user's completed quests.
*
* Slightly adapted from https://runescape.wiki/w/MediaWiki:Gadget-questchecker-core.js
*
* @author Jayden
* @author Andmcadams
* @author Jakesterwars
* @author Cook Me Plox
* @author Lezed1
* @author Haidro
*/
var CLASSES = {
QC_ACTIVE: "qc-active",
QC_INPUT: "qc-input",
QC_ICON: "rs-qc-icon"
};
var ENDPOINTS = {
osrs: "https://sync.runescape.wiki/runelite/player/username/STANDARD",
shatteredrelics: "https://sync.runescape.wiki/runelite/player/username/SHATTERED_RELICS_LEAGUE" //use actual url
};
var questCorrections = {
// Add corrections for API quest names -> wiki names here.
// API quest name is the key and the wiki page name is the value.
"Desert Treasure II - The Fallen Empire": "Desert Treasure II",
"Recipe for Disaster - Another Cook's Quest": "Recipe for Disaster/Another Cook's Quest",
"Recipe for Disaster - Culinaromancer": "Recipe for Disaster/Defeating the Culinaromancer",
"Recipe for Disaster - Mountain Dwarf": "Recipe for Disaster/Freeing the Mountain Dwarf",
"Recipe for Disaster - Wartface & Bentnoze": "Recipe for Disaster/Freeing the Goblin generals",
"Recipe for Disaster - Pirate Pete": "Recipe for Disaster/Freeing Pirate Pete",
"Recipe for Disaster - Lumbridge Guide": "Recipe for Disaster/Freeing the Lumbridge Guide",
"Recipe for Disaster - Evil Dave": "Recipe for Disaster/Freeing Evil Dave",
"Recipe for Disaster - King Awowogei": "Recipe for Disaster/Freeing King Awowogei",
"Recipe for Disaster - Sir Amik Varze": "Recipe for Disaster/Freeing Sir Amik Varze",
"Recipe for Disaster - Skrach Uglogwee": "Recipe for Disaster/Freeing Skrach Uglogwee"
},
icons = {
yes: ' <span class="' + CLASSES.QC_ICON + '"><img class="qc-complete" src="//oldschool.runescape.wiki/images/Yes_check.svg?00000" width="15px" ></span>',
no: ' <span class="' + CLASSES.QC_ICON + '"><img class="qc-not-started" src="//oldschool.runescape.wiki/images/X_mark.svg?00000" width="13px" ></span>'
};
var wikisync = {
/**
* Startup method
*/
init: function init() {
wikisync.createFields();
},
setCheckboxText: function setCheckboxText(text) {
$(".rs-wikisync-hide-completed .oo-ui-labelElement-label").each(function () {
$(this).text(text);
});
},
hideCompletedEntries: function hideCompletedEntries() {
var selected = wikisync.hideCompletedCheckbox.isSelected();
if (selected) {
$(".wikisync-completed").hide();
}
},
/**
* Creates the input fields for the user's RSN
*/
createFields: function createFields() {
var name;
if (rs.hasLocalStorage() === true) {
$.removeCookie("RSN", {
path: "/"
}); // remove any existing cookies using jQuery, will return false if it doesn't exist so it's fine
name = localStorage.getItem("rsn");
} else {
name = wikisync.getCookie("RSN");
}
var gamemode = "osrs";
$("." + CLASSES.QC_INPUT).each(function () {
var input1 = new OO.ui.TextInputWidget({
placeholder: "Display name",
id: "rs-qc-rsn"
});
if (name) {
// Set input to cookie/localStorage value.
input1.setValue(name);
}
var button1 = new OO.ui.ButtonInputWidget({
label: new OO.ui.HtmlSnippet('<img src="' + rs.getFileURLCached("RuneLite icon.png") + '" width=' + '"20px" />' + " Look up"),
title: "Look up player data using RuneLite",
flags: ["primary", "progressive"],
classes: ["wikisync-lookup-button"]
});
var leagueOnly = $(this).hasClass("league-only");
if (leagueOnly) {
gamemode = "shatteredrelics";
}
var button1action = function button1action() {
if (rs.hasLocalStorage() === true) {
localStorage.setItem("rsn", input1.value); // save in localStorage
} else {
wikisync.setCookie("RSN", input1.value, 30); // set a cookie for 30 days
}
wikisync.loadData(input1.value, gamemode);
};
button1.on("click", button1action);
input1.on("enter", button1action);
var helpModalBtn = new OO.ui.ButtonWidget({
label: "Learn how to enable WikiSync",
href: "/w/RuneScape:WikiSync"
});
var hideCompleted = false;
if (rs.hasLocalStorage()) {
if (localStorage.getItem("wikisync-hide-completed") === "true") {
hideCompleted = true;
}
}
wikisync.hideCompletedCheckbox = new OO.ui.CheckboxInputWidget({
selected: hideCompleted
});
wikisync.hideCompletedCheckbox.on("change", function () {
var selected = wikisync.hideCompletedCheckbox.isSelected();
if (rs.hasLocalStorage() === true) {
localStorage.setItem("wikisync-hide-completed", selected); // save in localStorage
}
$(".wikisync-completed").toggle(!selected);
});
var fieldset = new OO.ui.FieldsetLayout({
id: "rs-qc-form"
});
var fieldSetItems = [new OO.ui.FieldLayout(input1, {
label: "Username:",
align: "inline"
})];
fieldSetItems.push(button1);
fieldset.addItems([new OO.ui.HorizontalLayout({
items: fieldSetItems
}), new OO.ui.FieldLayout(helpModalBtn, {
label: "No data found. To use this, enable the WikiSync plugin in RuneLite.",
align: "inline",
classes: ["rs-wikisync-help"]
}), new OO.ui.LabelWidget({
label: "Missing some data from RuneLite for this page. Please log in to the game to re-sync.",
classes: ["rs-wikisync-missingdata"]
}), new OO.ui.FieldLayout(wikisync.hideCompletedCheckbox, {
label: "Hide completed",
align: "inline",
classes: ["rs-wikisync-hide-completed"]
})]);
if ($(this).hasClass("lighttable")) {
// If it's a lighttable, insert the fieldset before the table
fieldset.$element.insertBefore(this);
} else {
// If not, insert it inside the element that has the class
$(this).prepend(fieldset.$element);
}
// Hide all of the help elements to start with
$(".rs-wikisync-help").hide();
$(".rs-wikisync-missingdata").hide();
if ($(".srl-tasks, .music-tracks").length === 0) {
// only show checkbox if it's a table with hide-able tasks
$(".rs-wikisync-hide-completed").hide();
}
});
if (name) {
// If there is a saved name, load the data for it.
wikisync.loadData(name, gamemode);
}
},
/**
* Updates the status text
*/
updateStatus: function updateStatus(text) {
mw.notify(text, {
tag: "wikisync"
});
},
/**
* Sets a cookie
*/
setCookie: function setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
},
/**
* Returns the value of a cookie, or null if it doesn't exist
*/
getCookie: function getCookie(name) {
var cookie = new RegExp("^(?:.*;)?\\s*" + name + "\\s*=\\s*([^;]+)(?:.*)?$"),
match = document.cookie.match(cookie);
if (match !== null) {
return match[1];
} else {
return null;
}
},
/**
* Load data
*/
loadData: function loadData(rsn, gamemode) {
if (!rsn) {
wikisync.updateStatus("Invalid RSN");
return;
}
var endpoint = ENDPOINTS[gamemode || "osrs"] || ENDPOINTS.osrs;
// Hide help text if it is showing.
$(".rs-wikisync-help").hide();
$(".rs-wikisync-missingdata").hide();
$(".wikisync-success").remove();
$.ajax({
// Get the quest data
type: "GET",
url: endpoint.replace("username", rsn),
dataType: "json",
success: function success(msg) {
var userQuests = {};
Object.entries(msg.quests).forEach(function (q) {
var k = q[0],
v = q[1];
// Correct quest names to wiki page names
if (k in questCorrections) {
var correctName = questCorrections[k];
userQuests[correctName] = v;
} else {
userQuests[k] = v;
}
});
var userSkills = {};
Object.entries(msg.levels).forEach(function (q) {
var k = q[0],
v = q[1];
userSkills[k] = v;
});
$("." + CLASSES.QC_ICON).remove();
$(".wikisync-completed").show();
$(".wikisync-completed").removeClass("wikisync-completed");
$("<img>").attr("src", "//oldschool.runescape.wiki/images/f/fb/Yes_check.svg?00000").addClass("wikisync-success").css("width", "20px").css("height", "20px").css("position", "relative").insertAfter(".wikisync-lookup-button");
var hasAllData = [wikisync.addQuestIcons(userQuests), wikisync.addQuestTable(userQuests, userSkills, msg.achievement_diaries), wikisync.addDiaryTable(msg.achievement_diaries), wikisync.addSkillTable(userSkills), wikisync.addSkillIcons(userSkills), wikisync.addMusicTracks(msg.music_tracks), wikisync.addCombatAchievementTasks(msg.combat_achievements)].every(function (result) {
return result;
});
if (!hasAllData) {
$(".rs-wikisync-missingdata").show();
}
},
error: function error(req) {
$("." + CLASSES.QC_ICON).remove();
wikisync.setCheckboxText("Hide completed");
if (req.responseJSON && req.responseJSON.code && req.responseJSON.code === "NO_USER_DATA") {
$(".rs-wikisync-help").show();
} else {
wikisync.updateStatus("There was a problem loading data for " + rsn);
}
}
});
},
/**
* Clicks the Combat Achievement rows
*/
addCombatAchievementTasks: function addCombatAchievementTasks(combatAchievements) {
var combatAchievementTable = $('table.' + CLASSES.QC_ACTIVE + '.ca-tasks');
if (combatAchievementTable.length === 0) {
// Page doesn't have Combat Achievement tasks on it
return true;
}
if (combatAchievementTable === null) {
return false;
}
var seen = {};
combatAchievements.forEach(function (taskId) {
seen[taskId] = true;
});
combatAchievementTable.each(function () {
$(this).find("tr[data-ca-task-id]").each(function () {
var task_id = $(this).data("ca-task-id");
if (!!seen[task_id] !== $(this).hasClass("highlight-on")) {
$(this).click();
}
if (seen[task_id]) {
$(this).addClass("wikisync-completed");
}
});
});
return true;
},
/**
* Clicks the music track rows
*/
addMusicTracks: function addMusicTracks(musicTracks) {
var musicTable = $("table." + CLASSES.QC_ACTIVE + ".music-tracks");
if (musicTable.length === 0) {
// Not a music track page
return true;
}
if (musicTracks === null) {
// Missing data
return false;
}
var total = 0;
var completed = 0;
musicTable.each(function () {
$(this).find("tr[data-music-track-name]").each(function () {
var music_track_name = $(this).data("music-track-name");
if (!!musicTracks[music_track_name] !== $(this).hasClass("highlight-on")) {
$(this).click();
}
if (musicTracks[music_track_name]) {
$(this).addClass("wikisync-completed");
completed++;
}
total++;
});
});
wikisync.setCheckboxText("Hide unlocked tracks (" + completed + "/" + total + " unlocked)");
wikisync.hideCompletedEntries();
return true;
},
/**
* Append a checkmark/X icon to `element`.
*/
append_icon: function append_icon(element, completed) {
if (completed) {
$(element).append(icons.yes);
} else {
$(element).append(icons.no);
}
},
/**
* Clicks the rows in a table of question and diary tiers. Also appends icons to rows dedicated to skill training
*/
addQuestTable: function addQuestTable(quests, skills, achievementDiaries) {
function splitOnLastOccurence(str, splitOn) {
var index = str.lastIndexOf(splitOn);
return {
before: str.slice(0, index),
after: str.slice(index + 1)
};
}
// Quest and diary completion
$("table." + CLASSES.QC_ACTIVE + ".oqg-table tr[data-rowid]").each(function () {
var rowID = $(this).data("rowid");
var isAchievementDiary = rowID.includes("Diary#");
if (isAchievementDiary) {
// Achievement diary rowIDs are formatted as "$NAME Diary#$TIER", where "$NAME" may contain spaces.
var diaryName = splitOnLastOccurence(rowID, " ").before;
var diaryTier = splitOnLastOccurence(rowID, "#").after;
if (diaryName in achievementDiaries && diaryTier in achievementDiaries[diaryName] && "complete" in achievementDiaries[diaryName][diaryTier]) {
var diaryCompleted = achievementDiaries[diaryName][diaryTier].complete;
if (diaryCompleted !== null) {
if (diaryCompleted !== $(this).hasClass("highlight-on")) {
$(this).click();
}
}
}
} else {
var questName = rowID;
if (questName in quests) {
var questCompleted = quests[questName] == 2;
if (questCompleted !== $(this).hasClass("highlight-on")) {
$(this).click();
}
}
}
});
// Skill training complete
$("table." + CLASSES.QC_ACTIVE + ".oqg-table tr[data-skill][data-skill-level]").each(function () {
var skillName = $(this).data("skill");
skillName = skillName.charAt(0).toUpperCase() + skillName.slice(1);
var skillLevel = $(this).data("skill-level");
var row = $(this).find("th");
wikisync.append_icon(row, skills[skillName] >= skillLevel);
});
return true;
},
// Clicks cells/rows in a table based on skill levels.
addSkillTable: function addSkillTable(skills) {
$("table." + CLASSES.QC_ACTIVE + ".skill-table [data-skill][data-skill-level]").each(function () {
var skillName = $(this).data("skill");
var skillLevel = $(this).data("skill-level");
var skillCompleted = skills[skillName] >= skillLevel;
if (skillCompleted !== $(this).hasClass("highlight-on")) {
$(this).click();
}
});
return true;
},
// Clicks rows in a table based on achievement diary task completion
addDiaryTable: function addDiaryTable(achievementDiaries) {
var hasAllData = true;
$("table." + CLASSES.QC_ACTIVE + ".diary-table[data-diary-name][data-diary-tier]").each(function () {
var task_index = -1;
var diaryName = $(this).data("diary-name");
var diaryTier = $(this).data("diary-tier");
$(this).find("tr").each(function () {
if (task_index < 0) {
task_index += 1;
return;
}
if (diaryName in achievementDiaries && diaryTier in achievementDiaries[diaryName] && achievementDiaries[diaryName][diaryTier].tasks.length > task_index) {
var task_completed = achievementDiaries[diaryName][diaryTier].tasks[task_index];
if (task_completed !== null) {
if (task_completed !== $(this).hasClass("highlight-on")) {
$(this).click();
}
} else {
hasAllData = false;
}
}
task_index += 1;
});
});
return hasAllData;
},
/**
* Adds the icons next to respective quests
*/
addQuestIcons: function addQuestIcons(quests) {
$("." + CLASSES.QC_ACTIVE + " a").each(function () {
if ($(this).html().toLowerCase() != "expand" || $(this).html().toLowerCase() != "collapse") {
var questTitle = $(this).text().trim();
if (questTitle in quests) {
wikisync.append_icon(this, quests[questTitle] === 2);
}
}
});
return true;
},
/**
* Adds the icons next to respective skills
*/
addSkillIcons: function addSkillIcons(userLevels) {
$("." + CLASSES.QC_ACTIVE + " .scp").each(function () {
var level = $(this).data("level");
var skill = $(this).data("skill");
if (typeof level !== "number" || userLevels[skill] === undefined) {
return;
}
wikisync.append_icon(this, userLevels[skill] >= level);
});
return true;
}
};
$(wikisync.init);