Kanka Subpage Elements Counter

Shows the count of attributes, relations, assets, etc. on each entity's corresponding submenu item

  1. // ==UserScript==
  2. // @name Kanka Subpage Elements Counter
  3. // @namespace http://tampermonkey.net/
  4. // @license MIT
  5. // @version 5
  6. // @description Shows the count of attributes, relations, assets, etc. on each entity's corresponding submenu item
  7. // @author Salvatos
  8. // @match https://app.kanka.io/*
  9. // @icon https://www.google.com/s2/favicons?domain=kanka.io
  10. // @connect kanka.io
  11. // @grant GM_addStyle
  12. // ==/UserScript==
  13.  
  14. // Get JSON export URL for the current entity
  15. const exportLink = document.querySelector('a[href$=".json"]');
  16.  
  17. if (exportLink) {
  18.  
  19. var apiURL = exportLink.href;
  20.  
  21. // Request JSON for the target entity
  22. var xhr = new XMLHttpRequest();
  23. xhr.open("GET", apiURL, true);
  24. xhr.responseType = 'json';
  25. xhr.onload = function (e) {
  26. if (xhr.readyState === 4) {
  27. if (xhr.status === 200) {
  28. let abilities = xhr.response.data.entity_abilities.length,
  29. attributes = xhr.response.data.attributes.length,
  30. events = xhr.response.data.entity_events.length,
  31. inventory = xhr.response.data.inventory.length,
  32. elements = (xhr.response.data.elements) ? xhr.response.data.elements.length : null;
  33.  
  34. // Quick little function for recurring HTML
  35. function badgeTag(withVar) {
  36. return `<div class="badge float-right border">${withVar}</div>`;
  37. }
  38.  
  39. // Abilities
  40. if (abilities > 0) {
  41. document.querySelector('.entity-menu a[href$="/entity_abilities"]').insertAdjacentHTML("beforeend", badgeTag(abilities));
  42. }
  43. // Attributes
  44. if (attributes > 0) {
  45. document.querySelector('.entity-menu a[href$="/attributes"]').insertAdjacentHTML("beforeend", badgeTag(attributes));
  46. }
  47. // Events/reminders
  48. if (events > 0) {
  49. document.querySelector('.entity-menu a[href$="/entity_events"]').insertAdjacentHTML("beforeend", badgeTag(events));
  50. }
  51. // Inventory
  52. if (inventory > 0) {
  53. document.querySelector('.entity-menu a[href$="/inventory"]').insertAdjacentHTML("beforeend", badgeTag(inventory));
  54. }
  55. // Quest elements (Kanka only shows elements that are entities, not "loose" ones)
  56. if (elements > 0) {
  57. // If there’s already a count, update it instead of creating a new badge
  58. if (document.querySelector('.entity-menu a[href$="/quest_elements"] .badge')) {
  59. document.querySelector('.entity-menu a[href$="/quest_elements"] .badge').innerHTML = elements;
  60. }
  61. else {
  62. document.querySelector('.entity-menu a[href$="/quest_elements"]').insertAdjacentHTML("beforeend", badgeTag(elements));
  63. }
  64. }
  65. // Assets are already handled by Kanka like child entities
  66. // Relations not provided (only pinned relations, which we can already see)
  67.  
  68. } else {
  69. console.error(xhr.statusText);
  70. }
  71. }
  72. };
  73. xhr.onerror = function (e) {
  74. console.error(xhr.statusText);
  75. };
  76. xhr.send(null);
  77. }
  78.  
  79. GM_addStyle(`
  80. /* More sensible font size for "badges" in the sidebar */
  81. .entity-submenu .badge {
  82. font-size: .750rem;
  83. }
  84. `);