Enhancement Userscript for LIHKG

An Enhancement Userscript for LIHKG

Pada tanggal 10 Juni 2021. Lihat %(latest_version_link).

  1. // ==UserScript==
  2. // @name Enhancement Userscript for LIHKG
  3. // @version 0.2
  4. // @description An Enhancement Userscript for LIHKG
  5. // @include /https?\:\/\/lihkg\.com/
  6. // @icon https://www.google.com/s2/favicons?domain=lihkg.com
  7. // @grant GM_addStyle
  8. // @namespace https://greasyfork.org/users/371179
  9. // ==/UserScript==
  10. (function() {
  11. 'use strict';
  12. GM_addStyle(`
  13. .EGBBkGyEbfIEpHMLTW84H:not([dragmode]),.EGBBkGyEbfIEpHMLTW84H[dragmode="text"]{position:fixed;left:-9999px;top:-9999px;width:2px;height:2px;}
  14. div[contenteditable] p>img~br:last-child,div[contenteditable] p>a~br:last-child,div[contenteditable] p>div~br:last-child{content:'';}
  15. `)
  16. //fix copy editing
  17.  
  18. var getElementText = function(el) {
  19. var text = '';
  20. // Text node (3) or CDATA node (4) - return its text
  21. if ((el.nodeType === 3) || (el.nodeType === 4)) {
  22. text = el.nodeValue;
  23. // If node is an element (1) and an img, input[type=image], or area element, return its alt text
  24. } else if ((el.nodeType === 1) && (
  25. (el.tagName.toLowerCase() == 'img') ||
  26. (el.tagName.toLowerCase() == 'area') ||
  27. ((el.tagName.toLowerCase() == 'input') && el.getAttribute('type') && (el.getAttribute('type').toLowerCase() == 'image'))
  28. )) {
  29. text = el.getAttribute('alt') || '';
  30. if (el.tagName.toLowerCase() == 'img' && text == '' && el.getAttribute('src')) {
  31.  
  32. text = '[img]' + el.getAttribute('src') + '[/img]';
  33. }
  34. // Traverse children unless this is a script or style element
  35. } else if ((el.nodeType === 1) && (
  36. (el.tagName.toLowerCase() == 'br')
  37. )) {
  38. text = '\n';
  39. // Traverse children unless this is a script or style element
  40. } else if ((el.nodeType === 1) && !el.tagName.match(/^(script|style)$/i)) {
  41. var children = el.childNodes;
  42. for (var i = 0, l = children.length; i < l; i++) {
  43. text += getElementText(children[i]);
  44. }
  45. }
  46. return text;
  47. };
  48.  
  49.  
  50. document.cssAll = function() {
  51.  
  52. var s = document.querySelectorAll.apply(this, arguments)
  53.  
  54. s = Array.prototype.slice.call(s, 0)
  55. return s
  56. }
  57.  
  58. function urlConvert(url) {
  59. var src = url.replace(/\w+\:\/\//, '')
  60. var replacements = [...src.matchAll(/[\w\.]+/g)].filter((t) => /\./.test(t))
  61. if (replacements.length > 1) {
  62. replacements.length--;
  63.  
  64. }
  65. replacements.forEach((s) => {
  66. src = src.replace(s, '')
  67. })
  68.  
  69. src = src.replace(/\/+/g, '/')
  70.  
  71. return src;
  72.  
  73. }
  74.  
  75. var emoji = {};
  76.  
  77. setInterval(() => {
  78.  
  79. document.cssAll('img[src*="lihkg.com"][alt]:not([title])').forEach(function(imgElm) {
  80. var src = imgElm.getAttribute('src');
  81. var erc = urlConvert(src)
  82. var imgAlt = imgElm.getAttribute('alt') || "";
  83. if (/^[\x20-\x7E]+$/.test(imgAlt) && /\#/.test(imgAlt)) {
  84. emoji[erc] = imgAlt.trim()
  85. }
  86.  
  87. imgElm.setAttribute('title', imgAlt)
  88.  
  89. })
  90.  
  91.  
  92. document.cssAll('a[href*="profile/"]:not([href*="//"]):not([title])').forEach(function(aElm) {
  93. aElm.setAttribute('title', aElm.getAttribute('href'))
  94. })
  95.  
  96. document.cssAll('[data-ic~="hkgmoji"]:not([title])>img[src*="lihkg.com"]:not([alt])').forEach(function(imgElm) {
  97. var src = imgElm.getAttribute('src');
  98. var erc = urlConvert(src)
  99. var text = emoji[erc] ? emoji[erc] : "[img]" + erc + "[/img]"
  100. imgElm.parentNode.setAttribute('title', text)
  101. imgElm.setAttribute('alt', text)
  102.  
  103.  
  104. })
  105.  
  106. document.cssAll('a[href*="local.lihkg.com"]>img:not([anchored])').forEach(function(img) {
  107. img.setAttribute('anchored', 'true')
  108.  
  109.  
  110. var originalSrc = img.getAttribute('src') || img.getAttribute('data-original') || ""
  111. var newSrc = originalSrc.replace('local.lihkg.com', 'cdn.lihkg.com');
  112.  
  113. if (newSrc && originalSrc != newSrc) {
  114.  
  115. console.log(originalSrc, newSrc)
  116.  
  117. var fx = function() {
  118. if (img.complete == false) return setTimeout(fx, 33);
  119.  
  120. if (img.currentSrc == "") {
  121.  
  122. var b = img.cloneNode(false);
  123. b.removeAttribute('data-original');
  124. b.removeAttribute('data-src');
  125.  
  126. if (b.getAttribute('alt') == "") b.removeAttribute('alt')
  127. if (b.getAttribute('title') == "") b.removeAttribute('title')
  128.  
  129. b.setAttribute('src', newSrc);
  130. img.parentNode.replaceChild(b, img)
  131.  
  132. if (b.parentNode.getAttribute('href')) {
  133. b.parentNode.setAttribute('href', b.parentNode.getAttribute('href').replace(originalSrc, newSrc));
  134. if (b.nextElementSibling && b.nextElementSibling.hasAttribute('data-error')) b.nextElementSibling.parentNode.removeChild(b.nextElementSibling);
  135. if (b.nextElementSibling && b.nextElementSibling.outerHTML.toLocaleLowerCase() == '<ins></ins>') b.nextElementSibling.parentNode.removeChild(b.nextElementSibling);
  136.  
  137.  
  138.  
  139. }
  140.  
  141. b.removeAttribute('anchored')
  142.  
  143.  
  144. }
  145.  
  146. }
  147. fx();
  148.  
  149.  
  150. }
  151.  
  152. })
  153.  
  154.  
  155. document.cssAll('div[contenteditable] div[data-ic][contenteditable="false"]').forEach((elm) => {
  156.  
  157. elm.removeAttribute('contenteditable')
  158. })
  159.  
  160.  
  161.  
  162.  
  163. }, 33)
  164.  
  165.  
  166. var makePlain = false;
  167. document.addEventListener('drop', function(evt) {
  168. console.log(evt, makePlain, evt.target)
  169.  
  170. var p = evt.target;
  171. var contenteditable = false;
  172. while (p) {
  173. if (p.hasAttribute('contenteditable') && p.getAttribute('contenteditable') != 'false') {
  174. contenteditable = true;
  175. break;
  176. }
  177. p = p.parentNode;
  178.  
  179. }
  180.  
  181. if (contenteditable) {
  182.  
  183. if (makePlain && evt.dataTransfer.getData('text/html')) {
  184.  
  185. var text = evt.dataTransfer.getData('text/html');
  186.  
  187.  
  188. setTimeout(function() {
  189. var sel = window.getSelection();
  190. if (sel.getRangeAt && sel.rangeCount) {
  191.  
  192.  
  193. var range = sel.getRangeAt(0);
  194.  
  195. var cloneContents = range.cloneContents();
  196.  
  197.  
  198. var hh = document.createElement('html')
  199. hh.innerHTML = text;
  200. var hhPlain = getElementText(hh)
  201. hh.innerText = hhPlain
  202.  
  203.  
  204. if (cloneContents.textContent !== hhPlain) {
  205.  
  206. range.deleteContents();
  207.  
  208. document.execCommand('insertHTML', false, '<p>' + hh.innerHTML.toLowerCase().replace("<br />", "<br>").replace("<br/>", "<br>").replace("<br>", "<br></p><p>") + "</p>");
  209. }
  210.  
  211. }
  212.  
  213. }, 10);
  214. }
  215.  
  216. }
  217.  
  218.  
  219. }, true)
  220.  
  221.  
  222. document.addEventListener('dragstart', function(evt) {
  223. var editable = document.querySelector('div[contenteditable]')
  224. var dragFrom = evt.target
  225. if (editable && dragFrom) {
  226.  
  227. if (editable == dragFrom || editable.contains(dragFrom)) {
  228.  
  229. } else {
  230. makePlain = true;
  231.  
  232. }
  233.  
  234. }
  235. console.log(evt)
  236. }, false);
  237.  
  238.  
  239. document.addEventListener('dragend', function(evt) {
  240. if (Event.prototype._preventDefault) {
  241. Event.prototype.preventDefault = Event.prototype._preventDefault
  242. Event.prototype._preventDefault = null
  243.  
  244. }
  245. setTimeout(function() {
  246. makePlain = false;
  247. }, 77);
  248. }, false);
  249.  
  250. document.addEventListener('drop', function(evt) {
  251.  
  252. setTimeout(function() {
  253. makePlain = false;
  254. }, 77);
  255. if (Event.prototype._preventDefault) {
  256. Event.prototype.preventDefault = Event.prototype._preventDefault
  257. Event.prototype._preventDefault = null
  258. }
  259.  
  260. var dropZone = document.querySelector('.EGBBkGyEbfIEpHMLTW84H');
  261. if (!dropZone) return;
  262. dropZone.removeAttribute('dragmode');
  263.  
  264.  
  265. }, true)
  266.  
  267.  
  268.  
  269. document.addEventListener('dragenter', function(evt) {
  270.  
  271. var dropZone = document.querySelector('.EGBBkGyEbfIEpHMLTW84H');
  272.  
  273.  
  274.  
  275. var isFileTransfer = false;
  276. if (evt.dataTransfer.types) {
  277. for (var i = 0; i < evt.dataTransfer.types.length; i++) {
  278. if (evt.dataTransfer.types[i] == "Files") {
  279. isFileTransfer = true;
  280. break;
  281. }
  282. }
  283. }
  284.  
  285. if (!isFileTransfer) {
  286.  
  287. if (dropZone)
  288. dropZone.setAttribute('dragmode', 'text');
  289. // evt.dataTransfer.effectAllowed='copy';
  290. if (!Event.prototype._preventDefault) {
  291. Event.prototype._preventDefault = Event.prototype.preventDefault;
  292. Event.prototype.preventDefault = function() {
  293. if (this.type == 'dragover') {
  294.  
  295. } else {
  296. return this._preventDefault();
  297. }
  298. //console.log(this)
  299. };
  300. }
  301.  
  302.  
  303.  
  304. } else {
  305. makePlain = false;
  306. if (dropZone)
  307. dropZone.setAttribute('dragmode', 'file');
  308.  
  309.  
  310. }
  311. // console.log('dragenter',!isFileTransfer)
  312.  
  313.  
  314.  
  315. }, false)
  316.  
  317.  
  318.  
  319.  
  320. // Your code here...
  321. })();