Wanikani Forums Global Framework

A framework for global script services on Wanikani forums

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greatest.deepsurf.us/scripts/27967/186167/Wanikani%20Forums%20Global%20Framework.js

  1. // ==UserScript==
  2. // @name Wanikani Forums Global Framework
  3. // @namespace rfindley
  4. // @description A framework for global script services on Wanikani forums
  5. // @version 1.0.3
  6. // @copyright 2017+, Robin Findley
  7. // @license MIT; http://opensource.org/licenses/MIT
  8. // ==/UserScript==
  9.  
  10. if (window.wkf_global === undefined) window.wkf_global = {};
  11.  
  12. (function(gobj) {
  13. if (gobj.already_loaded === true) return;
  14. gobj.already_loaded = true;
  15.  
  16. var settings_url = '/scripts/global';
  17.  
  18. var html =
  19. '<div class="settings">'+
  20. ' <h1>Global script settings</h1>'+
  21. ' <p>'+
  22. ' <label>Public API Key</label>'+
  23. ' <input id="apikey" value="" placeholder="Enter your API Key here" type="text" class="span6">'+
  24. ' <span class="note">(You can find it [<a href="https://www.wanikani.com/settings/account/" target="_">here</a>])</span>'+
  25. ' </p>'+
  26. ' <p>'+
  27. ' <label></label>'+
  28. ' <input id="save" type="submit" name="commit" value="Save" class="btn">'+
  29. ' <span id="save_status" class="note"></span>'+
  30. ' </p>'+
  31. ' <h1>Individual Script Settings</h1>'+
  32. ' <div id="script_list">'+
  33. ' </div>'+
  34. '</div>'+
  35. '';
  36.  
  37. var css =
  38. '.settings > h1 {padding-bottom: 0.2em; margin-bottom:0.5em; border-bottom:1px solid black;}'+
  39. '.settings > h1:not(:first-child) {margin-top:40px;}'+
  40. '.settings label {display:inline-block; text-align:right; padding-right:8px; width:120px;}'+
  41. '.settings .note {color:#aaa; margin-left:8px; font-size:0.9em;}'+
  42. '#save_status {color:#c22;}'+
  43. '.settings a {color:#c22;}'+
  44. '.settings .btn {'+
  45. ' border-color: rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25);'+
  46. ' color: #555;'+
  47. ' cursor: pointer;'+
  48. ' text-shadow: 0 1px 1px rgba(255,255,255,0.75);'+
  49. ' background-color: #f5f5f5;'+
  50. ' background-image: linear-gradient(to bottom, #fff, #e6e6e6);'+
  51. ' border: 1px solid #bbbbbb;'+
  52. ' border-radius: 4px;'+
  53. ' box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 1px 2px rgba(0,0,0,0.05);'+
  54. ' line-height: 1em;'+
  55. '}'+
  56. '';
  57.  
  58. // Load jquery (if not already).
  59. function load_jquery() {
  60. return new Promise(function(resolve, reject){
  61. if (typeof jQuery !== 'undefined') return resolve();
  62.  
  63. function jquery_loaded(){
  64. resolve();
  65. }
  66.  
  67. var headTag = document.getElementsByTagName("head")[0];
  68. var jqTag = document.createElement('script');
  69. jqTag.type = 'text/javascript';
  70. jqTag.src = 'https://code.jquery.com/jquery-3.1.1.min.js';
  71. jqTag.onload = jquery_loaded;
  72. headTag.appendChild(jqTag);
  73. });
  74. }
  75.  
  76. // Load
  77. if (window.location.pathname.match('^/scripts/') !== null) {
  78. document.getElementById('main-outlet').innerHTML = '';
  79. var promise = load_jquery();
  80. if (window.location.pathname === settings_url) {
  81. promise.then(function(){
  82. $('head').append('<style type="text/css">'+css+'</style>');
  83. $('#main-outlet').html(html);
  84. var apikey = localStorage.getItem('apikey');
  85. if (apikey !== null) {
  86. $('#apikey').val(apikey);
  87. }
  88. $('#save').on('click', function(){
  89. var apikey = $('#apikey').val();
  90. if (apikey.match(/^[0-9a-f]{32}$/) !== null) {
  91. localStorage.setItem('apikey', apikey);
  92. $('#save_status').text('Saved!').fadeIn(0).delay(750).fadeOut(750);
  93. } else {
  94. alert('API Key is not valid!');
  95. }
  96. });
  97. $('body').on('add_script', function(e){
  98. var data = e.detail;
  99. $('#script_list').append('<p class="partner_script"><a href="'+data.url+'">'+data.name+'</a></p>');
  100. $('.settings .partner_script').sort(function(a,b){
  101. return $(a).text().localeCompare($(b).text());
  102. }).appendTo($('#script_list'));
  103. });
  104. document.getElementsByTagName('body')[0].dispatchEvent(new Event('global_settings_done'));
  105. });
  106. }
  107. }
  108.  
  109. gobj.add_script = function(name, url) {
  110. if (window.location.pathname === '/scripts/global') {
  111. document.getElementsByTagName('body')[0].addEventListener('global_settings_done', function(){
  112. document.getElementsByTagName('body')[0].dispatchEvent(new CustomEvent('add_script', {detail:{name:name, url:url}}));
  113. });
  114. }
  115. };
  116.  
  117. gobj.get_apikey = function(force_renew) {
  118. if (force_renew === true) localStorage.removeItem('apikey');
  119. var apikey = localStorage.getItem('apikey') || '';
  120. if (apikey.match(/^[0-9a-f]{32}$/) !== null) return apikey;
  121. if (window.location.pathname !== '/scripts/global') window.location.pathname = '/scripts/global';
  122. return null;
  123. };
  124.  
  125. gobj.query_api = function(partial_url) {
  126. return new Promise(function(resolve, reject){
  127. var apikey = localStorage.getItem('apikey');
  128. if (apikey.match(/^[0-9a-f]{32}$/) === null) return reject();
  129. $.getJSON('https://www.wanikani.com/api/user/'+apikey+partial_url, function(json){
  130. if (json.error !== undefined) return reject(json.error);
  131. var current_user = $('#current-user img').attr('title');
  132. var api_user = json.user_information.username;
  133. if (current_user !== api_user) gobj.get_apikey(true /* force_renew */);
  134. resolve(json);
  135. });
  136. });
  137. };
  138.  
  139. gobj.goto_settings = function(reason) {
  140. if (window.location.pathname !== '/scripts/global') window.location.pathname = '/scripts/global';
  141. };
  142.  
  143. })(window.wkf_global);