CC98 Tools - Image Collections

为CC98网页版添加收藏图片功能

  1. // ==UserScript==
  2. // @name CC98 Tools - Image Collections
  3. // @namespace https://www.cc98.org/
  4. // @version 0.6
  5. // @description 为CC98网页版添加收藏图片功能
  6. // @author ml98
  7. // @license MIT
  8. // @match https://www.cc98.org/*
  9. // @match http://www-cc98-org-s.webvpn.zju.edu.cn:8001/*
  10. // @require https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js
  11. // @//require https://greasyfork.org/scripts/2199-waitforkeyelements/code/waitForKeyElements.js?version=6349
  12. // @require https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@6b9ca81bf32899b4274086aa9d48c3ce5648e0b6/waitForKeyElements.js
  13. // @require https://cdn.jsdelivr.net/gh/rvera/image-picker@5f9701bb928bf0be602cfd2af7b96b3316d060f3/image-picker/image-picker.js
  14. // @resource customCSS https://cdn.jsdelivr.net/gh/rvera/image-picker@5f9701bb928bf0be602cfd2af7b96b3316d060f3/image-picker/image-picker.css
  15. // @grant GM_addStyle
  16. // @grant GM_getResourceText
  17. // @grant GM_getValue
  18. // @grant GM_setValue
  19. // ==/UserScript==
  20.  
  21. let starttime=(new Date()).getTime();
  22. console.log("%cCC98 Tools", "font-size: large");
  23.  
  24. // update version and migrate data
  25. (function() {
  26. let version = GM_getValue('version');
  27. if(version !== '0.6'){
  28. GM_setValue('version', '0.6');
  29. console.log('update to version 0.6');
  30. let myFavoriteOldData = localStorage.getItem("myFavorite");
  31. if(myFavoriteOldData) {
  32. GM_setValue("myFavorite", myFavoriteOldData);
  33. }
  34. }
  35. })();
  36.  
  37. // image-selector CSS
  38. let newCSS = GM_getResourceText("customCSS");
  39. GM_addStyle(newCSS);
  40. GM_addStyle(`
  41. .image_picker_selector{ max-width: 1000px; position: relative; left: 50%; transform: translateX(-50%);}
  42. .thumbnail > .image_picker_image{width: auto; max-height: 180px; }
  43. `);
  44.  
  45. // 加载收藏的图片
  46. function readImgs(){
  47. 'use strict';
  48. let myFavorite = GM_getValue("myFavorite");
  49. let images = [];
  50. if(myFavorite) images = JSON.parse(myFavorite);
  51. return images;
  52. }
  53.  
  54. // 收藏图片
  55. function saveImg(imgSrc){
  56. 'use strict';
  57. let images = readImgs();
  58. let index = images.indexOf(imgSrc);
  59. if (index == -1){
  60. if(images.length >= 10){
  61. alert("收藏的图片过多,请删除一些图片!(Shift + Click)");
  62. return;
  63. }
  64. images.push(imgSrc);
  65. console.log("add", imgSrc);
  66. GM_setValue("myFavorite", JSON.stringify(images));
  67. }
  68. }
  69.  
  70. // 删除收藏的图片
  71. function removeImg(imgSrc){
  72. 'use strict';
  73. let images = readImgs();
  74. let index = images.indexOf(imgSrc);
  75. if (index > -1){
  76. images.splice(index, 1);
  77. console.log("remove", imgSrc);
  78. GM_setValue("myFavorite", JSON.stringify(images));
  79. }
  80. }
  81.  
  82. // 在图片左上角添加收藏按钮
  83. function addSaveButton(){
  84. 'use strict';
  85. console.log("addSaveButton");
  86. let toolbox = document.querySelector(".ubb-image-toolbox");
  87. if(toolbox.childElementCount == 5){
  88. let imgSrc = toolbox.nextSibling.getAttribute("src");
  89. let saveButton = document.createElement("button");
  90. saveButton.textContent = "💾";
  91. saveButton.onclick = function(){ saveImg(imgSrc); }
  92. toolbox.insertBefore(saveButton, toolbox.firstChild);
  93. }
  94. }
  95.  
  96. // 在ubb-editor添加图片选择按钮
  97. function addImagePickerButton(){
  98. 'use strict';
  99. console.log("addImagePickerButton");
  100. let imagePickerButton = document.querySelector(".fa-favorite");
  101. if(!imagePickerButton) imagePickerButton = createImagePickerButton();
  102. let referenceNode = document.querySelector("button.fa.fa-smile-o.ubb-button");
  103. referenceNode.parentNode.insertBefore(imagePickerButton, referenceNode.nextSibling);
  104. }
  105.  
  106. function createImagePickerButton(){
  107. 'use strict';
  108. console.log("createImagePickerButton");
  109. let imagePickerButton = document.createElement("button");
  110. imagePickerButton.className = "fa fa-favorite ubb-button";
  111. imagePickerButton.type = "button";
  112. imagePickerButton.title = "收藏";
  113. imagePickerButton.innerText = "📁";
  114. imagePickerButton.onclick = function(){
  115. let imagePickerSelector = document.querySelector(".ubb-editor > ul");
  116. let textarea = document.querySelector("textarea");
  117. if(!imagePickerSelector) {
  118. addImagePicker();
  119. textarea.style.display = "none";
  120. console.log("hide textarea");
  121. }
  122. else if (imagePickerSelector.style.display == "none") {
  123. imagePickerSelector.style.display = "block";
  124. textarea.style.display = "none";
  125. console.log("show imagePicker hide textarea");
  126. } else {
  127. imagePickerSelector.style.display = "none";
  128. textarea.style.display = "block";
  129. console.log("hide imagePicker show textarea");
  130. }
  131. }
  132. return imagePickerButton;
  133. }
  134.  
  135. // 添加图片选择器 https://github.com/rvera/image-picker
  136. function addImagePicker(){
  137. 'use strict';
  138. console.log("addImagePicker");
  139. let imagePicker = document.createElement("select");
  140. imagePicker.className = "image-picker masonry show-html";
  141. imagePicker.style.display = 'none';
  142. imagePicker.innerHTML = `<option data-img-class="first" value="0"></option>`;
  143. let imgs = readImgs();
  144. imgs.forEach(src => imagePicker.innerHTML += `<option data-img-src="` + src + `" value="` + src + `"></option>`);
  145. imagePicker.innerHTML += `<option data-img-class="last" value="0"></option>`
  146.  
  147. let referenceNode = document.querySelector(".ubb-emoji");
  148. referenceNode.parentNode.insertBefore(imagePicker, referenceNode.nextSibling);
  149.  
  150. $("select").imagepicker({
  151. selected: function(option, event){
  152. let select = document.querySelector(".ubb-editor > select");
  153. let textarea = document.querySelector("textarea");
  154.  
  155. // shift + click: remove
  156. if(event.shiftKey == true){
  157. removeImg(select.value);
  158. return;
  159. }
  160. console.log("select", select.value);
  161. // textarea.value = textarea.value + "[img]" + select.value +"[/img]";
  162. // https://stackoverflow.com/questions/61107351/simulate-change-event-to-enter-text-into-react-textarea-with-vanilla-js-script
  163. var nativeTextAreaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
  164. nativeTextAreaValueSetter.call(textarea, textarea.value + "[img]" + select.value +"[/img]");
  165. const evt = new Event('input', { bubbles: true});
  166. textarea.dispatchEvent(evt);
  167.  
  168. let imagePickerSelector = document.querySelector(".ubb-editor > ul");
  169. imagePickerSelector.style.display = "none";
  170. textarea.style.display = "block";
  171. }
  172. });
  173. }
  174.  
  175. function removeButton(){
  176. console.log("removeButton");
  177. let imagePickerButton = document.querySelector(".fa-favorite");
  178. if(imagePickerButton) imagePickerButton.remove();
  179. let imagePickerSelector = document.querySelector(".ubb-editor > ul");
  180. if(imagePickerSelector) imagePickerSelector.style.display = 'none';
  181. let textarea = document.querySelector("textarea");
  182. if(textarea) textarea.style.display = "block";
  183. // let TeXButton = document.querySelector(".fa-TeX");
  184. // if(TeXButton) TeXButton.remove();
  185. }
  186.  
  187. function addButton(){
  188. addImagePickerButton();
  189. // addTeXButton();
  190. }
  191.  
  192. waitForKeyElements(".ubb-image-toolbox", addSaveButton, false);
  193. waitForKeyElements(".fa-smile-o", addButton, false);
  194. waitForKeyElements(".ubb-preview", removeButton, false);
  195.  
  196. let endtime=(new Date()).getTime();
  197. console.log("script load in", endtime-starttime, "ms");